home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
CD ROM Paradise Collection 4
/
CD ROM Paradise Collection 4 1995 Nov.iso
/
hamradio
/
ax25_30.zip
/
AX25_30.PAS
Wrap
Pascal/Delphi Source File
|
1994-10-10
|
81KB
|
2,926 lines
"6809"
$RECURSIVE OFF$
$SEPARATE ON$
$EXTENSIONS ON$
$GLOBPROC ON$
{*****************************************************************
COPYRIGHT, (C) DAVID GEORGE HENDERSON III
HAROLD E. PRICE, 1982, 1983
Permission is granted for use so long as this notice of
authorship is retained in the source code.
******************************************************************}
{ Implementation notes:
Great pains have been taken to make this software as
transportable as possible. The use of sub-sets and character
strings have been specifically avoided. When modifying this
software, please keep that goal in mind.
The code also contains several kludges designed to avoid
bugs/limitations in the HP64000 compiler which was used to
produce the BETA version of the TAPR TNC. These primarily
occur in lines using the variables KLUDGE and W8FIX.
The WRITEn routines exist to improve transportability
between various versions of PASCAL used during the initial
testing. Please attempt to use them when adding new features.
The HP64000 PASCAL seems to have a problem with
IF NOT simple_boolean THEN. They have been changed to
IF simple_boolean = FALSE THEN
Harold E. Price, NK6K
David G. Henderson, KD4NL
Los Angeles, December 1982.
Changes made September 1983, DGH.
1. Ten calls in header implies up to 8 digipeats.
2. Low level routine LLRINF now called with link state on change.
3. Tracebit MONDIGI added. Forces all digipeated IFRAMES and UI frames to be monitored.
4. Tracebit DUMPDIGI added. Dumps all digipeated frames if not already monitored.
5. Automatic switchover to Vancouver mode removed. No more 'Vancouver virus'.
6. If a frame is monitored, it won't be shown as normal data.
7. The NEW parameter now has no meaning. Left in command table for debug operations.
8. DM now sent in AX25 when the TNC is not idle and a SABM is received from a foreign station.
9. '*** <call> busy' shows up on the station trying to connect to the busy station.
10. '*** CONNECT REQUEST: <CALL>' shows up on the busy station if not transparent.
11. Poll/Final bit usage: Will never send poll bit on timeout, never needs
final bit for timer recovery. When a poll bit is received in an IFRAME,
then one of RNR|REJ|RR with the final bit set is forced even if a
piggyback ack could be used. The poll/final bit is always ignored
in Vancouver mode.
This action can be disable with a trace bit.
WARNING: These changes must be made in other modules for this source!!!!!
1. The changed state table is kept in Pascal comments in the ROSEG declaration.
2. A 'BUSY' message has been added to the end of ROSEG.
Changes made October 1983 HEP.
1. MON flags moved to novram. MTO/MFROM ALL construct was
given a ghost flag in novram.
2. Parser error of blank line removed.
3. CWID ON|OFF and IDTEXT [text] added.
4. Full duplex command added
}
PROGRAM AX25MAIN;
CONST
XPIDBYTE = 240; { transmitted PID byte }
MODULO = 8;
MAXFRAME = 296;
PROMPTLEN = 4;
BUFRSIZE = 256;
NUMHDCALL =10 { max number of calls in header };
NHEADCH = 6; { kludge... number of header call characters }
NHEADSIZE = 7; { length of call with SSID byte }
TOCALLX = 1;
FRCALLX = 2;
RPCALLX = 3;
TYPE
CH6 = { packed } ARRAY[1..6] OF CHAR;
CH6X = { packed } ARRAY[1..NHEADCH] OF CHAR;
CH7 = { packed } ARRAY [1..7] OF CHAR;
CH128 = { packed } ARRAY [1..128] OF CHAR;
CH4096 = { packed } ARRAY[1..4096] OF CHAR;
CH5 = { packed } ARRAY[1..5] OF CHAR;
CH8 = { packed } ARRAY[1..8] OF CHAR;
CH10 = { packed } ARRAY[1..10] OF CHAR;
CH15 = { packed } ARRAY[1..15] OF CHAR;
CH20 = { packed } ARRAY[1..20] OF CHAR;
FTYPE = (F_NULL, F_CON, F_DISC);
LIT_TYPE = (L_FNULL, { must be first }
L_AFTER,
L_ALL,
L_CHAR,
L_CONVERS,
L_EVERY,
L_ID,
L_LINK,
L_OFF,
L_ON,
L_MONITOR,
L_NO,
L_NONE,
L_TERMINAL,
L_TIMING,
L_TRANS,
L_VIA,
L_YES,
L_LNULL); { must be last }
{ various commands that this system will accept }
COM_TYPE = (C_FNULL, { must be first }
C_ABAUD,
C_ABIT,
C_AUTOLF,
C_AWLEN,
C_AX25,
C_AXDELAY,
C_AXHANG,
C_BEACON,
C_BKONDEL,
C_BTEXT,
C_CONNECT,
C_CALIBRAT,
C_CANLINE,
C_CANPAC,
C_CMDTIME,
C_COMMAND,
C_CONMODE,
C_CONOK,
C_CONVERS,
C_CPACTIME,
C_CR,
C_CWID,
C_DISCONNE,
C_DEBUG,
C_DELETE,
C_DIGIPEAT,
C_DISPLAY,
C_DWAIT,
C_ECHO,
C_ESCAPE,
C_FLOW,
C_FRACK,
C_FULLDUP,
C_TRANS,
C_HBAUD,
C_ID,
C_IDTEXT,
C_LCOK,
C_LFADD,
C_MONITOR,
C_MONALL,
C_MAXFRAME,
C_MONCON,
C_MONFROM,
C_MONTO,
C_MYCALL,
C_MYVADR,
C_NULLS,
C_NUCR,
C_NULF,
C_PACLEN,
C_PACTIME,
C_PARITY,
C_PASS,
C_PERM,
C_PROGRAM,
C_RESET,
C_REDISP,
C_RETRY,
C_SCREENL,
C_SENDPAC,
C_START,
C_STOP,
C_TRACE,
C_TXDELAY,
C_TXFLOW,
C_UNPROTO,
C_VDIGIPEA,
C_VRPT,
C_XFLOW,
C_XMITOK,
C_XOFF,
C_XON,
C_LNULL); { must be last }
BUFTYPE = { packed } ARRAY [1..BUFRSIZE] OF CHAR;
BAUDTYPE = ARRAY [0..15] OF INTEGER;
HEADCALL = { packed } RECORD
CALL: CH6X;
SSID: CHAR;
END { RECORD };
POSHEAD = (CHARRAY,VANCHD,AX25HD);
VANTYPE = RECORD
VANID: CHAR;
VANCTL: CHAR;
FRCALL: CH6X;
TOCALL: CH6X;
END { RECORD };
HEADTYPE = RECORD
CASE POSHDJUNK:POSHEAD OF
CHARRAY: (CH: { packed } ARRAY[0..35]OF CHAR);
VANCHD: (VANCHEAD: VANTYPE);
AX25HD: (CALLS: { packed } ARRAY[1..NUMHDCALL] OF
HEADCALL);
END { CASE };
{ States the link may be in. These are exactly the same states
with exactly the same meanings as in the BX.25 document from AT&T.
Vancouver mode uses all the states except LS3. Events are altered in
this mode to reflect the sending of CONREQ,CONACK,DISREQ,DISACK }
LSTYPE = (LS1, { idle,disconnected }
LS2, { link setup, sending SABMs trying to get connected }
LS3, { frame rejected, I need to send FRMR and get UA }
LS4, { disconnect request, sending DISC and looking for UA }
LS5);{ information transfer. connedted & exchanging messages }
{ Events that may happen Some code depends on the order of events,
and all possible types of frames are events. }
EVTYPE = (OTHERFR, {0}
IFRAME, {1}
RR, {2}
RNR, {3}
REJ, {4}
UI, {5}
SABM, {6}
DISC, {7}
DM, {8}
UA, {9}
FRMR, {10}
T1RO, {11}
N2EXCEED,{12}
DISREQ, {13}
DISACK, {14}
CONREQ, {15}
CONACK {16});
{ Actions that may have to be taken as a result of event/state combos }
CNCACT = (NOP_CNC, {0}
UA_S5_CNC, {1}
DM_CNC, {2}
UA_CNC, {3}
DM_S1_CNC, {4}
UA_S1_CNC, {5}
M_S5_CNC, {6}
M_S1_CNC, {7}
SABM_S2_CNC,{8}
FRMR_CNC, {9}
DISC_CNC, {10}
SABM_CNC, {11}
CONR_CNC, {12}
CONA_CNC, {13}
DISR_CNC, {14}
DISA_CNC, {15}
BAILOUT_CNC,{16}
SAYBUSY_CNC){17};
{ Meaning of bits that can be set via TRACE command }
TRACEBIT = (DUMPFRAME, { x1xx dump all incoming frames }
DUMPSTATE, { x2xx show before, after in state change routine}
DUMPIFRAME, { x4xx incoming frames that look useful }
DUMPOFRAME, { x8xx dump outgoing frames }
DUMPFRMR, { 1xxx dump FRMR stuff, in and out }
DUMPALLD, { 2xxx dump data as well as header }
DUMPJUNK1,{ 4xxx spacer (full dup now command) }
DUMPJUNK2, { 8xxx spacer }
DUMPJUNK3, { xxx1 spacer }
DUMPJUNK4, { xxx2 spacer }
DUMPJUNK5, { xxx4 spacer }
DUMPJUNK6, { xxx8 spacer }
DUMPJUNK7, { xx1x spacer }
MONDIGI, { xx2x allow digipeated frames to get monitored }
DUMPDIGI, { xx4x dump any digipeated frames that dont get monitored }
DONTFINL); { xx8x never send the final bit }
TIMER = RECORD
RUNNING,PENDING: BOOLEAN;
TSTOP: INTEGER;
END;
FRCHTYPE = { packed } ARRAY[0..MAXFRAME] OF CHAR;
MONLIST = RECORD
CNT: 0..NUMHDCALL; { number of calls in list }
ALL: BOOLEAN; { when CNT = 0; TRUE = all calls, FALSE = no calls }
CALLS: HEADTYPE;
END { RECORD };
ACTYPE = RECORD { assembler communications area }
{ beginning of EEPROM data }
LFADD: BOOLEAN; { add LF in outgoing packet after CR }
NUCR: BOOLEAN; { send nulls after CR }
NULF: BOOLEAN; { send nulls after LF }
ESCAPE: BOOLEAN; { Print $ for escape }
LCOK: BOOLEAN; { Don't translate lower to upper on display }
BKONDEL: BOOLEAN; { Backspace when delete character entered}
ECHO: BOOLEAN; { Echo terminal input characters }
AUTOLF: BOOLEAN; { insert LF after CR on display }
XFLOW: BOOLEAN; { set for XON/XOFF, reset for hardware only }
FLOW: BOOLEAN; { flow control }
DELCHR: BOOLEAN; { delete character }
RPTOK: BOOLEAN; { be an AX.25 digipeater }
VANCDP: BOOLEAN; { OK to be a Vancouver digipeater }
CONOK: BOOLEAN; { OK to connect }
XMITOK: BOOLEAN; { OK to transmit }
AX25: BOOLEAN; { originate AX.25; reset means Vancouver }
PCEVY: BOOLEAN; { packet timeout EVERY or AFTER }
CONMODE: BOOLEAN; { auto connect mode default }
VRPT: BOOLEAN; { VDIGIPEAT this packet }
CR: BOOLEAN; { insert SENDPAC at end of CONVERS packet }
CPT: BOOLEAN; { use PACTIME in CONVERSE }
TXF: BOOLEAN; { use XFLOW in TRANSPARENT }
CWID: BOOLEAN; { CWID every 9.5 min if set }
BECEVY: BOOLEAN; { beacon every (set) or after (reset) }
FULLDUP: BOOLEAN; { assume full duplex link }
MONON: BOOLEAN; { monitor mode on }
MONCON: BOOLEAN; { monitor while connected }
MONALL: BOOLEAN; { monitor others' connected frames }
MONTO: BOOLEAN; { set equal to MON.TOLIST.ALL }
MONFROM: BOOLEAN; {set equal to MON.FROMLIST.ALL }
SCWID: INTEGER; { screen width }
PLEN: INTEGER; { packet data length }
XTRA: CHAR; { space filler }
CLCHR: CHAR; { cancel line character }
CPCHR: CHAR; { cancel packet character }
STPCHR: CHAR; { stop character from terminal }
STRCHR: CHAR; { start character from terminal }
PASCHR: CHAR; { pass-character character }
RDSCHR: CHAR; { redispaly-line character }
SPCHR: CHAR; { send-packet character }
CMDCHR: CHAR; { command-mode character }
DBGCHR: CHAR; { enter-debug mode character }
XFFCHR: CHAR; { stop character from TNC }
XONCHR: CHAR; { start character from TNC }
VANID: CHAR; { Vancouver address }
MYCALL: HEADCALL; { call sign of this TNC, extension in 7th byte }
KV7D: CHAR; { dummy byte }
HBAUD: INTEGER; { HDLC baud rate }
NULLS: INTEGER; { number of nulls*2 after a <cr> or <lf> }
RETRY: INTEGER; { packet retry count }
IFTIME: INTEGER; { frame timeout time for retry }
KMAX: INTEGER; { max frames in flight }
TXDLY: INTEGER; { transmit keyup delay }
AXDLY: INTEGER; { audio repeater keyup delay }
AXHANG: INTEGER; { audio repeater hang time }
PCTIME: INTEGER; { packet timeout time for transparent mode }
CMTIME: INTEGER; { command timeout value for transparent mode }
DWAIT: INTEGER; { digipeat wait time }
BECTIM: INTEGER; { beacon time }
ABAUD: INTEGER; { terminal baud rate }
ABIT: INTEGER; { number of stop bits }
AWLEN: INTEGER; { Word length }
PARITY: INTEGER; { Terminal parity }
{ end of EEPROM data }
AIRP: INTEGER; { termainl input removal pointer }
CBPRES: BOOLEAN; { command buffer present }
HOFC: INTEGER; { number of bytes available for frame }
AOFC: INTEGER; { terminal output free count }
BECLEN: INTEGER; { BTEXT length }
IDLEN: INTEGER; { alternate CWID length }
TICKER: INTEGER; { gets incremented every clock tick }
DCDDRP: BOOLEAN; { set when DCD drops }
DCD: BOOLEAN; { actual modem signal itself }
DIGOUT: BOOLEAN; { set when sending digipeat frame }
RETOUT: BOOLEAN; { set when retrying frame }
HITSZ: INTEGER; { HDLC input top size -- number of bytes in top frame }
MODEF1: BOOLEAN; { TRUE = command mode, FALSE = other }
MODEF2: BOOLEAN; { TRUE = converse mode, FALSE = transparent mode }
HACT: BOOLEAN; { set when HDLC frames are present in the output queue }
T1,TBEACON: TIMER;
UCONCNT: INTEGER; { unconnected list size }
END;
ACTYPEY= RECORD
BECTXT: CH128; { BEACON text string }
IDTXT: CH128; { alternate CWID text }
END;
STATEVAR = 0..7;
FLMARK = RECORD
RP: INTEGER; { removal poineter in terminal ring buffer }
CNT: INTEGER; { count of data characters in this frame }
END { FLMARK };
POSFRAME = 1..4;
FRTYPE = RECORD
CASE IIII:POSFRAME OF
1: (FRVAN: VANTYPE);
2: (CH: FRCHTYPE);
3: (CALLS: { packed } ARRAY[1..NUMHDCALL] OF HEADCALL);
4: (DMRHEAD: HEADTYPE; { kludge to send DM when busy });
END { RECORD };
ROTYPE = RECORD
COMTEXT: ARRAY[1..74] OF CH8;
LITTEXT: ARRAY[1..17] OF CH8;
HEXCHAR: { packed } ARRAY[1..16] OF CHAR;
ABAUD: BAUDTYPE;
HBAUD: BAUDTYPE;
MSG: RECORD
EH: CH5; { init 'EH? ' }
ON: CH5; { init ' ON ' }
OFF: CH5; { init ' OFF ' }
WAS: CH5; { init 'was ' }
PROMPT: CH5; { init 'cmd: ' }
LINKSTATE: CH15; { init 'Link state is: ' }
DISCON: CH15; { init 'DISCONNECTED ' }
CONTO: CH15; { init 'CONNECTED to ' }
CANTCON: CH15; { init 'Can''t CONNECT, ' }
IGNORED: CH15; { init 'Input ignored' }
VALUEOUT: CH20; { init 'Value out of range ' }
CONINPROG: CH20; { init 'CONNECT in progress ' }
FRMRINPROG: CH20; { init 'FRMR in progress ' }
DISCINPROG: CH20; { init 'DISC in progress ' }
CANTDISC: CH20; { init 'Can''t DISCONNECT, '}
NOTWHILE: CH20; { init 'not while connedted '}
END;
CNCACTION: ARRAY[LSTYPE,SABM..N2EXCEED,BOOLEAN] OF CNCACT;
{ 13,1,0,2,0,0,0,0
0,0,12,8,0,0,13,3
15,4,0,17,6,6,0,5
12,11,16,16,0,1,0,0
0,0,0,8,0,8,0,9
16,16,0,2,15,3,7,7
0,7,0,0,14,10,16,16
13,1,15,5,0,0,0,8
0,8,0,0,16,16 }
VANCMAP: ARRAY[DISREQ..CONACK] OF EVTYPE;
{ 7,8,6,9 }
TICKSPS: INTEGER; { number of clock ticks per second }
ZEROVAR: INTEGER; { always zero }
TITLERDFR: CH10; { init 'frame read' }
TITLEUSFR: CH10; { init 'frame used' }
TITLEOUTFR: CH10; { init 'frame sent' }
STATEMOD: CH10; { init 'state mod:' }
RETRYZERO: CH20; { init 'retry count exceeded' }
CONRQMSG: CH20; { init '*** connect request:' }
FRMRSENT: CH10; { init 'FRMR sent ' }
FRMRRCVD: CH10; { init 'FRMR rcvd' }
BEACON: CH6X; { init 'BEACON' }
CQ: CH6X; { init 'CQ ' }
BUSYMSG: CH5; { init ' BUSY' }
END;
VAR
$EXTVAR ON$
ROEXTVAR: ROTYPE;
ACX: ACTYPE;
ACY: ACTYPEY;
MON: RECORD
FRLIST: MONLIST;
TOLIST: MONLIST;
END { monitor structure };
$EXTVAR OFF$
{ globasl required by parser to be in outer block }
$GLOBVAR ON$
CONCALL: HEADCALL;
CNCCALL: HEADTYPE;
NMODEF2: BOOLEAN; { TRUE = converse mode, FALSE = transparent mode }
CNCCNT: 0..NUMHDCALL;
TRACEDATA: RECORD
CASE BJUNK:BOOLEAN OF
FALSE: (BITS: SET OF TRACEBIT);
TRUE: (NUMBR: INTEGER);
END { RECORD };
UCONLST: HEADTYPE; { unconnected call list }
{ All of these variables are necessary to keep track of one link state }
RETRY_SIP: BOOLEAN; { set when retry send of I frames happening }
RETRY_SEQ: INTEGER; { If RETRY_SIP, then last frame sequence number for retry }
FLFIRST: INTEGER; { index of first frame in flight }
FLCUR: INTEGER; { number of frame to be send next }
FLNEXT: INTEGER; { index of next frame to be constructed }
NR: INTEGER; { next sequence number expected from other side }
RETRYCNT: -1..127;
XRETRY: -1..127; { -1 means do it forever }
LS: LSTYPE;
CONHEAD: HEADTYPE;
CONHDSIZE: INTEGER;
OFRMRBUF: ARRAY[1..8] OF CHAR; { outgoing FRMR frame information field }
SENDRNR,RCVDRNR,SENDREJ,SENDRR,SENDFIN: BOOLEAN;
RNRSIZE: INTEGER;
FLINFO: ARRAY[STATEVAR] OF FLMARK;
REMVANID: INTEGER; { Vancouver protocol ID number of other guy if connected }
PARSERES: FTYPE;
TICKTEMP: INTEGER; { avoids overflow problems in timer manipulation }
LASTCALL: INTEGER;
$GLOBVAR OFF$
PROCEDURE FLSHAI(VAR RP: INTEGER);
EXTERNAL;
PROCEDURE GETAI(VAR RP: INTEGER; VAR N: INTEGER; VAR A: FRCHTYPE; VAR X: INTEGER);
EXTERNAL;
PROCEDURE WRAPAI(VAR OLDRP: INTEGER; { input }
VAR N: INTEGER; VAR NEWRP: INTEGER { output });
EXTERNAL;
PROCEDURE PUTAO(VAR A: FRCHTYPE; VAR X: INTEGER; VAR N: INTEGER);
EXTERNAL;
PROCEDURE GETHI(VAR C: FRCHTYPE; VAR N: INTEGER);
EXTERNAL;
PROCEDURE PUTHO(VAR A: FRCHTYPE; VAR N: INTEGER);
EXTERNAL;
PROCEDURE CALIBR;
EXTERNAL;
PROCEDURE PROGRM;
EXTERNAL;
PROCEDURE CWID;
EXTERNAL;
PROCEDURE RESET1;
EXTERNAL;
PROCEDURE PUTNV; { repack NOVRAM, no burn }
EXTERNAL;
PROCEDURE PUTNVB; { repack NOVRAM and burn it }
EXTERNAL;
PROCEDURE GETCMD (VAR BUF: BUFTYPE; VAR ARS: INTEGER);
EXTERNAL;
PROCEDURE SETMOD;
EXTERNAL;
PROCEDURE CALCFC;
EXTERNAL;
PROCEDURE LLRINF(LS: INTEGER);
EXTERNAL;
{
PROCEDURE HDLCABORT;
EXTERNAL;
}
PROCEDURE REALAX25;
FORWARD;
PROCEDURE AX25;
BEGIN
REALAX25;
END;
{ This set of procedures exists to increase the transportability
of the Pascal portion of the AX.25 code }
PROCEDURE WRITE5(VAR C: CH5; J: INTEGER);
EXTERNAL;
PROCEDURE WRITE8(VAR C: CH8; J: INTEGER);
EXTERNAL;
PROCEDURE WRITE10(VAR C: CH10; J: INTEGER);
EXTERNAL;
PROCEDURE WRITE15(VAR C: CH15; J: INTEGER);
EXTERNAL;
PROCEDURE WRITE20(VAR C: CH20; J: INTEGER);
EXTERNAL;
PROCEDURE WRITE128(VAR C: CH128; J: INTEGER);
EXTERNAL;
PROCEDURE WRITE1(C: CHAR);
EXTERNAL;
PROCEDURE WRITEBLK;
EXTERNAL;
PROCEDURE WRITEINT(INT: INTEGER);
VAR HOLD: CH20;
I,J: INTEGER;
BEGIN
I := 0;
REPEAT
BEGIN
I := I+1;
HOLD[I] := CHR(ORD('0') + INT MOD 10);
INT := INT DIV 10;
END
UNTIL INT = 0;
FOR J := 0 TO I-1 DO
WRITE1(HOLD[I-J]);
END;
PROCEDURE WRITEHEX(HEX: INTEGER);
VAR HOLD: CH20;
I,J: INTEGER;
BEGIN
I := 0;
REPEAT
BEGIN
I := I+1;
HOLD[I] := ROEXTVAR.HEXCHAR[1 + SHIFT(SHIFT(HEX,12),-12)];
HEX := SHIFT(HEX,-4);
END;
UNTIL HEX = 0;
IF I = 1 THEN
WRITE1('0');
FOR J := 0 TO I-1 DO
WRITE1(HOLD[I-J]);
END;
PROCEDURE WRITELAST; { write a <cr> }
EXTERNAL;
PROCEDURE DISINT(INT: INTEGER);
BEGIN
WRITEBLK;
WRITEINT(INT);
END;
PROCEDURE DISHEX(HEX: INTEGER);
BEGIN
WRITEBLK;
WRITE1('$');
WRITEHEX(HEX);
END;
PROCEDURE DISCHR(CH: CHAR);
BEGIN
DISHEX(ORD(CH));
END;
PROCEDURE DISCALL(C: HEADCALL); { must not be VAR, part of kludge }
VAR I: 0..255;
BEGIN
FOR I := 1 TO 6 DO
IF C.CALL[I] <> ' ' THEN
WRITE1(C.CALL[I]);
IF ORD(C.SSID) <> 0 THEN
BEGIN
WRITE1('-');
WRITEINT(ORD(C.SSID));
END;
END;
PROCEDURE DISCLIST(CLIST: HEADTYPE; START: INTEGER; N: INTEGER);
{ write N calls in CLIST array starting at START }
VAR J: INTEGER;
BEGIN
N := N + START - 1;
FOR J := START TO N DO
BEGIN
DISCALL(CLIST.CALLS[J]);
IF J <> N THEN
WRITE1(',');
END;
END;
PROCEDURE HEXDUMP(VAR CH: FRCHTYPE; NBYTES: INTEGER; VAR TITLE: CH10);
VAR
JCHAR: CHAR;
I: INTEGER;
J: INTEGER;
SI: INTEGER;
LINE: INTEGER;
BEGIN
WRITE10(TITLE,10);
WRITELAST;
I := 0;
WHILE NBYTES > 0 DO
BEGIN
IF NBYTES < 16 THEN
LINE := NBYTES
ELSE
LINE := 16;
SI := I;
WRITEHEX(I);
WRITE1('-');
FOR J := 1 TO LINE DO
BEGIN
WRITEHEX(ORD(CH[I]));
IF (I MOD 4) = 3 THEN
WRITEBLK;
I := I + 1;
END;
FOR J := 1 TO 4 + 2*((16-LINE) MOD 4) + 9*((16-LINE) DIV 4) DO
WRITEBLK;
IF ((16-LINE) MOD 4)<> 0 THEN
WRITEBLK;
I := SI;
FOR J := 1 TO LINE DO
BEGIN
JCHAR := CHR(ORD(CH[I]) DIV 2);
IF (JCHAR >= ' ') AND (JCHAR <= '~') THEN
WRITE1(JCHAR)
ELSE
WRITE1('.');
I := I+1;
END;
I := SI;
FOR J := 1 TO 3 + (16-LINE) DO
WRITEBLK;
FOR J := 1 TO LINE DO
BEGIN
JCHAR := CHR((ORD(CH[I])*2) DIV 2);
IF (JCHAR >= ' ') AND (JCHAR <= '~') THEN
WRITE1(JCHAR)
ELSE
WRITE1('.');
I := I + 1;
END;
WRITELAST;
NBYTES := NBYTES - LINE;
END;
END;
PROCEDURE LAPBPROC(COMEV: FTYPE);
{ does the LAPB protocol using the procedures
MAKEHEAD, INTOS5, SHIPOUT, SHIPSUP, SHIPUI,
ACKFLIGHT, GETMYFRAME, CNCDSC, SENDFRMR }
VAR DATAORIG,NRCALC: INTEGER;
REVMID,REVHI,REV: 0..NUMHDCALL;
{ The following variables are set if GETMYFRAME returns TRUE }
FRCLASS: EVTYPE;
VS,VR: INTEGER;
PFBIT: BOOLEAN;
NDATA,DOFFSET: INTEGER;
LOCFRSIZE,LOCHDSIZE: INTEGER;
LOCFRAME: FRTYPE;
LOCHEAD: HEADTYPE;
WASMON: BOOLEAN;
PROCEDURE MAKEHEAD(REMCON: BOOLEAN; VAR INHEAD: HEADTYPE; N: INTEGER;
VAR OUTHEAD: HEADTYPE; VAR OUTHDSIZE: INTEGER);
{ INHEAD is the header structure, right justified.
OUTHEAD is the resulting structure, ready to send.
N is the number of calls, excluding MYCALL.
REMCON is true if the connect originates from another station.
Construct OUTHEAD and OUTHDSIZE to place in front of all frames. }
VAR I,J,K: INTEGER;
BEGIN
IF ACX.AX25 THEN
BEGIN { AX25 mode }
IF REMCON THEN
FOR I:=N DOWNTO 2 DO
OUTHEAD.CALLS[RPCALLX+I-2] := INHEAD.CALLS[RPCALLX+N-I]
ELSE
OUTHEAD := INHEAD;
OUTHEAD.CALLS[FRCALLX] := ACX.MYCALL;
IF N<=0 THEN
BEGIN
IF N=0 THEN
N := 1
ELSE
N := -N;
OUTHEAD.CALLS[TOCALLX].CALL := ROEXTVAR.BEACON;
OUTHEAD.CALLS[TOCALLX].SSID := CHR(0);
END
ELSE
OUTHEAD.CALLS[TOCALLX] := INHEAD.CALLS[FRCALLX];
OUTHDSIZE := NHEADSIZE*(N+1);
IF REMCON THEN
BEGIN { remote connection, must set up CNCCALL }
CNCCALL := OUTHEAD;
CNCCALL.CALLS[FRCALLX] := INHEAD.CALLS[FRCALLX];
CNCCNT := N;
END { remote connect stuff };
FOR I:=N+1 DOWNTO 1 DO
OUTHEAD.CALLS[I].SSID
:= CHR((ORD(OUTHEAD.CALLS[I].SSID) MOD 16)+48);
FOR I:=0 TO OUTHDSIZE-1 DO
OUTHEAD.CH[I] := CHR(2*ORD(OUTHEAD.CH[I]));
OUTHEAD.CH[OUTHDSIZE-1] := SUCC(OUTHEAD.CH[OUTHDSIZE-1]);
END { AX25 mode }
ELSE
BEGIN { Vancouver mode }
OUTHDSIZE := 1;
IF REMCON THEN { more remote connect stuff }
CNCCNT := 1;
IF ((ORD(INHEAD.VANCHEAD.VANID)> 128) AND REMCON) OR
(ACX.VRPT AND NOT REMCON) THEN
OUTHEAD.CH[0] := CHR(ORD(ACX.VANID)+128)
ELSE
OUTHEAD.CH[0] := ACX.VANID;
END { Vancouver mode }
END { MAKEHEAD };
PROCEDURE INTOS5;
{ sets global variables up whenever I'm moving into S5, information transfer }
BEGIN { INTOS5 };
ACX.RETOUT := FALSE;
FLFIRST := 0;
FLCUR := 0;
FLNEXT := 0;
NR := 0;
SENDRNR := FALSE;
SENDFIN := FALSE;
RCVDRNR := FALSE;
RNRSIZE := 0;
SENDRR := FALSE;
SENDREJ := FALSE;
FLINFO[0].RP := ACX.AIRP;
ACX.T1.RUNNING := FALSE;
ACX.T1.PENDING := FALSE;
RETRYCNT := XRETRY;
IF LS<>LS5 THEN
BEGIN { issue connect message if not in transparent }
IF ACX.MODEF1 OR NMODEF2 OR ACX.MODEF2 THEN
BEGIN
WRITE20(ROEXTVAR.CONRQMSG,4);
WRITE15(ROEXTVAR.MSG.CONTO,13);
DISCALL(CONCALL);
WRITELAST;
END;
ACX.MODEF1 := FALSE;
ACX.MODEF2 := NMODEF2;
SETMOD; { tell LLR of mode change }
END;
LS := LS5;
RETRY_SIP := FALSE;
END;
FUNCTION SHIPOUT: BOOLEAN;
{ Send out I frames.
Parameter FLCUR is FLFIRST if frames are to be retransmitted,
otherwise it is FLNEXT. }
VAR I,NEXTRP,NBYTES,NHEADC: INTEGER;
DONE: BOOLEAN;
BEGIN { SHIPOUT }
{ Assign new sequence numbers to I frames; that is, if new frames can
be generated, mark their starting position and count in terminal input ring.
If any I frames were sent out, return TRUE. }
DONE := FALSE;
SHIPOUT := FALSE;
REPEAT
DONE := ((FLNEXT-FLFIRST+MODULO) MOD 8) >= ACX.KMAX;
IF DONE = FALSE THEN
BEGIN
WRAPAI(FLINFO[FLNEXT].RP,NBYTES,NEXTRP);
IF NBYTES=0 THEN
DONE := TRUE
ELSE
BEGIN
FLINFO[FLNEXT].CNT := NBYTES;
FLNEXT := SUCC(ORD(FLNEXT)) MOD 8;
FLINFO[FLNEXT].RP := NEXTRP;
END;
END;
UNTIL DONE;
{ Insert CONHEAD into local frame }
IF FLCUR<>FLNEXT THEN
FOR I:=0 TO CONHDSIZE-1 DO
LOCFRAME.CH[I] := CONHEAD.CH[I];
NHEADC := CONHDSIZE + 1 + ORD(ACX.AX25 );
CALCFC; { insert something into ACX.HOFC }
{ Now send all I frames from FLCUR up to (but not including) FLNEXT }
WHILE (FLCUR<>FLNEXT) AND ((FLINFO[FLCUR].CNT+NHEADC) <= ACX.HOFC) DO
BEGIN
SHIPOUT := TRUE;
LOCFRAME.CH[NHEADC-1] := CHR(XPIDBYTE) { here is the magic PID byte!!! };
LOCFRAME.CH[CONHDSIZE] := CHR((NR*16+FLCUR)*2);
GETAI(FLINFO[FLCUR].RP,FLINFO[FLCUR].CNT,LOCFRAME.CH,NHEADC);
NBYTES := NHEADC+FLINFO[FLCUR].CNT;
IF DUMPOFRAME IN TRACEDATA.BITS THEN
BEGIN { show outgoing frame }
IF DUMPALLD IN TRACEDATA.BITS THEN
HEXDUMP(LOCFRAME.CH,NBYTES,ROEXTVAR.TITLEOUTFR)
ELSE
HEXDUMP(LOCFRAME.CH,NHEADC,ROEXTVAR.TITLEOUTFR);
END { trace stuff };
ACX.DIGOUT := FALSE;
PUTHO(LOCFRAME.CH,NBYTES);
CALCFC; { put something into ACX.HOFC }
FLCUR := SUCC(ORD(FLCUR)) MOD 8;
IF FLCUR=RETRY_SEQ THEN { last frame in retry sequence sent }
RETRY_SIP:=FALSE;
IF FALSE = (ACX.T1.RUNNING OR ACX.T1.PENDING OR RETRY_SIP) THEN
BEGIN
ACX.T1.PENDING := TRUE;
ACX.T1.TSTOP := ACX.IFTIME*ROEXTVAR.TICKSPS*CNCCNT;
END;
END;
END { SHIPOUT };
FUNCTION SHIPSUP(VAR HD: HEADTYPE; HDSIZE: INTEGER;
CNTRL: CHAR; NDAT: INTEGER): BOOLEAN;
{ If enough room exists in HDLC output ring, send out frame
with the control byte passed as a parameter and SHIPOUT TRUE }
VAR NBYTES,NHEADC,I: INTEGER;
BEGIN { SHIPSUP }
NHEADC := HDSIZE + 1;
NBYTES := NHEADC + NDAT;
CALCFC; { calculate ACX.HOFC }
IF NBYTES < ACX.HOFC THEN
BEGIN
SHIPSUP := TRUE;
FOR I:=0 TO HDSIZE-1 DO
LOCFRAME.CH[I] := HD.CH[I];
LOCFRAME.CH[HDSIZE] := CNTRL;
IF DUMPOFRAME IN TRACEDATA.BITS THEN
BEGIN { show outgoing frame }
IF DUMPALLD IN TRACEDATA.BITS THEN
HEXDUMP(LOCFRAME.CH,NBYTES,ROEXTVAR.TITLEOUTFR)
ELSE
HEXDUMP(LOCFRAME.CH,NHEADC,ROEXTVAR.TITLEOUTFR);
END { trace stuff };
ACX.DIGOUT := FALSE;
PUTHO(LOCFRAME.CH,NBYTES);
END
ELSE
SHIPSUP := FALSE;
END { SHIPSUP };
PROCEDURE SHIPUI(FROMAI: BOOLEAN);
{ Send out a UI frame from a beacon timeout, or disconnected input }
VAR NBYTES,NEWRP,NINFO,I: INTEGER;
BEGIN { SHIPUI }
IF FROMAI THEN
BEGIN { get data from terminal ring }
IF ACX.UCONCNT=0 THEN
BEGIN
ACX.UCONCNT := 1;
UCONLST.CALLS[FRCALLX].CALL := ROEXTVAR.CQ;
UCONLST.CALLS[FRCALLX].SSID := CHR(0);
END;
MAKEHEAD(FALSE,UCONLST,ACX.UCONCNT,LOCHEAD,LOCHDSIZE);
WRAPAI(ACX.AIRP,NINFO,NEWRP);
NBYTES := LOCHDSIZE + 1 + ORD(ACX.AX25);
LOCFRAME.CH[LOCHDSIZE+1] := CHR(XPIDBYTE);
GETAI(ACX.AIRP,NINFO,LOCFRAME.CH,NBYTES);
END { data from terminal ring }
ELSE
BEGIN { data from beacon buffer }
MAKEHEAD(FALSE,UCONLST,-ACX.UCONCNT,LOCHEAD,LOCHDSIZE);
NINFO := ACX.BECLEN;
NBYTES := LOCHDSIZE + ORD(ACX.AX25);
LOCFRAME.CH[LOCHDSIZE+1] := CHR(XPIDBYTE);
FOR I:=1 TO ACX.BECLEN DO
LOCFRAME.CH[NBYTES+I] := ACY.BECTXT[I];
END;
IF SHIPSUP(LOCHEAD,LOCHDSIZE,CHR(03) {UI} ,NINFO+ORD(ACX.AX25)) THEN
IF FROMAI THEN
FLSHAI(NEWRP);
END { SHIPUI };
FUNCTION ACKFLIGHT(VR: INTEGER): BOOLEAN;
{ Acknowledge all frames up to VR;
return TRUE if VR parameter is valid,
otherwise return FALSE }
VAR FRNO: INTEGER;
NEMPTIED: INTEGER;
BEGIN
FRNO := FLFIRST;
NEMPTIED := 0;
WHILE (FRNO<>FLNEXT) AND (VR<>FRNO) DO
BEGIN
NEMPTIED := NEMPTIED+FLINFO[FRNO].CNT;
FRNO := SUCC(ORD(FRNO)) MOD 8;
END;
IF VR<>FRNO THEN
ACKFLIGHT := FALSE
ELSE
BEGIN
FLSHAI(FLINFO[VR].RP);
ACKFLIGHT := TRUE;
IF VR<>FLFIRST THEN
BEGIN { at least one frame acknowledged }
IF VR<>FLNEXT THEN
BEGIN { there are still frames outstanding }
ACX.T1.TSTOP := ACX.TICKER+ACX.IFTIME*ROEXTVAR.TICKSPS;
ACX.T1.RUNNING := TRUE;
ACX.T1.PENDING := FALSE;
RETRYCNT := XRETRY;
ACX.RETOUT := FALSE;
RETRY_SIP := FALSE;
END
ELSE
BEGIN { all frames ACKed }
ACX.T1.RUNNING := FALSE;
ACX.T1.PENDING := FALSE;
ACX.RETOUT := FALSE;
RETRY_SIP := FALSE;
END;
END;
FLFIRST := VR;
END;
END { ACKFLIGHT };
PROCEDURE DISPREQ;
{ Show connect request message }
BEGIN {DISPREQ}
IF ACX.MODEF1 OR ACX.MODEF2 THEN
BEGIN
WRITE20(ROEXTVAR.CONRQMSG,20);
DISCALL(LOCHEAD.CALLS[FRCALLX]);
WRITELAST;
END;
END { DISPREQ };
FUNCTION GETMYFRAME: BOOLEAN;
{ Primary function is to read frames and note which frames are useful.
1. Checks for incoming frame present. If no frame present, return FALSE.
2. Extract header of frame.
3. If this frame is to be digipeated and if room exists, move to HDLC
output buffer. Return FALSE for the funtion value.
4. See if this frame is for me. If so, return TRUE for function value.
A quick look at the control byte classifies the kind of record,
and the header has been moved into LOCHEAD.
5. Sets the global boolean 'WASMON' if this frame was monitored.
}
VAR HMAX,CBYTE,CBYTESP,I: INTEGER;
RPTCALL,RPTBIT: INTEGER;
FORME,DISPMON,MATCH,WASDIGI,IFDIGI,ISCONCALL: BOOLEAN;
FUNCTION CHKLIST(VAR L: MONLIST; C: HEADCALL): BOOLEAN;
{ Checks for presence of callsign in a monitor list }
VAR I,J,K: 0..255;
RESULT: BOOLEAN;
BEGIN { CHKLIST }
RESULT := (L.CNT=0) AND L.ALL;
FOR I := L.CNT DOWNTO 1 DO
RESULT := RESULT OR (L.CALLS.CALLS[I].CALL=C.CALL);
CHKLIST := RESULT;
END { CHKLIST };
PROCEDURE TESTCOM;
{ Strips off the poll/final bit;
checks for IFRAME,RR,RNR,REJ,UI type frames }
VAR X: 0..255;
BEGIN
PFBIT := FALSE;
IF (CBYTE MOD 32) >=16 THEN
BEGIN
CBYTESP := CBYTE - 16;
PFBIT := TRUE
END
ELSE
CBYTESP := CBYTE;
X := CBYTE MOD 16;
VS := (CBYTE DIV 2) MOD 8;
VR := (CBYTE DIV 32);
DOFFSET := LOCHDSIZE + 1 + ORD(ACX.AX25);
NDATA := LOCFRSIZE - DOFFSET;
IF ODD(CBYTE) = FALSE THEN
FRCLASS := IFRAME
ELSE IF CBYTESP = 3 THEN
FRCLASS := UI
ELSE IF X=1 THEN
FRCLASS := RR
ELSE IF X=5 THEN
FRCLASS := RNR
ELSE IF X=9 THEN
FRCLASS := REJ;
DISPMON := ((FRCLASS=UI) OR ((FRCLASS=IFRAME) AND ACX.MONALL)) AND ACX.MONON AND
(ACX.MONCON OR (LS=LS1)) AND (ACX.MODEF2 OR ACX.MODEF1);
IFDIGI :=((FRCLASS=UI) OR (FRCLASS=IFRAME))
AND WASDIGI AND (MONDIGI IN TRACEDATA.BITS);
END { TESTCOM };
BEGIN { GETMYFRAME }
WASMON := FALSE;
WASDIGI := FALSE;
GETMYFRAME := FALSE;
FRCLASS := OTHERFR;
IF ACX.HITSZ<>0 THEN
BEGIN
IF FALSE = ACX.BECEVY THEN
BEGIN
ACX.TBEACON.RUNNING := ACX.BECTIM<>0;
ACX.TBEACON.TSTOP := ACX.TICKER + ROEXTVAR.TICKSPS*ACX.BECTIM*10;
END;
LOCFRSIZE := ACX.HITSZ;
IF LOCFRSIZE>MAXFRAME THEN
BEGIN { too big for me }
LOCFRSIZE := MAXFRAME;
GETHI(LOCFRAME.CH,LOCFRSIZE);
END
ELSE
BEGIN { frame fits }
DISPMON := FALSE;
FORME := FALSE;
GETHI(LOCFRAME.CH,LOCFRSIZE);
IF DUMPFRAME IN TRACEDATA.BITS THEN BEGIN { show frame in hex }
HEXDUMP(LOCFRAME.CH,LOCFRSIZE,ROEXTVAR.TITLERDFR); END;
CALCFC; { calculate ACX.HOFC }
CASE ACX.AX25 OF
FALSE :
BEGIN
IF ACX.VANCDP AND (ORD(LOCFRAME.FRVAN.VANID)>128)
AND (ORD(LOCFRAME.FRVAN.VANID)<160) THEN
BEGIN { digipeat in Vancouver mode }
IF LOCFRSIZE < ACX.HOFC THEN
BEGIN
ACX.DIGOUT := TRUE;
LOCFRAME.FRVAN.VANID := CHR(32+ORD(LOCFRAME.FRVAN.VANID));
PUTHO(LOCFRAME.CH,LOCFRSIZE);
WASDIGI := TRUE;
END;
END;
LOCHEAD.VANCHEAD := LOCFRAME.FRVAN;
LOCHDSIZE := 1;
CBYTE := ORD(LOCFRAME.FRVAN.VANCTL);
FORME := (LOCFRSIZE=14) AND
((ORD(LOCFRAME.FRVAN.VANID)>=161) OR
(ORD(LOCFRAME.FRVAN.VANID)<=127)) AND
(LOCFRAME.FRVAN.TOCALL=ACX.MYCALL.CALL);
FRCLASS := OTHERFR;
MATCH := (ORD(LOCHEAD.VANCHEAD.VANID)=REMVANID)AND(LS<>LS1);
TESTCOM;
IF CBYTE=23 { connect request } THEN
BEGIN
FRCLASS := CONREQ;
IF LS=LS1 THEN
BEGIN
NMODEF2 := ACX.CONMODE;
MAKEHEAD(TRUE,LOCHEAD,0,CONHEAD,CONHDSIZE);
CONCALL.CALL := LOCFRAME.FRVAN.FRCALL;
CONCALL.SSID := CHR(0);
GETMYFRAME := FORME;
REMVANID := ORD(LOCFRAME.FRVAN.VANID);
END
ELSE
GETMYFRAME := FORME AND (LOCFRAME.FRVAN.FRCALL=CONCALL.CALL);
END
ELSE IF CBYTE=7 { connect ACK } THEN
BEGIN
IF LOCFRAME.FRVAN.FRCALL=CONCALL.CALL THEN
BEGIN
FRCLASS := CONACK;
GETMYFRAME:=FORME;
REMVANID := ORD(LOCFRAME.FRVAN.VANID);
END
END
ELSE IF CBYTE=83 { disconnect req } THEN
BEGIN
FRCLASS := DISREQ;
GETMYFRAME := MATCH;
END
ELSE IF CBYTE=67{ disconnect ACK } THEN
BEGIN
FRCLASS := DISACK;
GETMYFRAME := MATCH;
END
ELSE
GETMYFRAME:=MATCH;
IF DISPMON OR IFDIGI THEN
BEGIN { monitor mode stuff }
DISINT(ORD(LOCFRAME.CH[0]));
WRITE1(':');
PUTAO(LOCFRAME.CH,DOFFSET,NDATA);
WRITELAST;
WASMON := TRUE;
END { monitor mode stuff };
END { nondigipeat Vancouver };
TRUE :
BEGIN { AX25 mode }
RPTBIT := 0;
LOCHDSIZE := 0;
HMAX := NUMHDCALL*NHEADSIZE;
REPEAT
LOCHEAD.CH[LOCHDSIZE] := CHR(ORD(LOCFRAME.CH[LOCHDSIZE])DIV 2);
LOCHDSIZE := SUCC(LOCHDSIZE);
UNTIL ODD(ORD(LOCFRAME.CH[LOCHDSIZE-1]))
OR (LOCHDSIZE>HMAX);
LASTCALL := LOCHDSIZE DIV NHEADSIZE;
FOR I:=1 TO LASTCALL DO
WITH LOCHEAD.CALLS[I] DO
BEGIN
IF ORD(SSID)>64 THEN
RPTBIT := I;
SSID := CHR(ORD(SSID) MOD 16);
END;
IF LASTCALL>2 THEN BEGIN
IF RPTBIT=0 THEN
RPTBIT := 3
ELSE
RPTBIT := RPTBIT + 1; END
ELSE
RPTBIT := 3;
RPTCALL := RPTBIT;
IF ((LOCHDSIZE MOD NHEADSIZE)=0 )
AND (LASTCALL>1) AND (LOCFRSIZE>LOCHDSIZE) THEN
BEGIN
IF (RPTCALL<=LASTCALL) AND
(LOCHEAD.CALLS[RPTCALL].SSID=ACX.MYCALL.SSID) AND
(LOCHEAD.CALLS[RPTCALL].CALL=ACX.MYCALL.CALL) THEN
BEGIN { frame to digipeat }
LOCFRAME.CALLS[RPTBIT].SSID := CHR(ORD(LOCFRAME.CALLS[RPTBIT].SSID)+128);
ACX.DIGOUT := TRUE;
IF (LOCFRSIZE < ACX.HOFC) AND ACX.RPTOK THEN
PUTHO(LOCFRAME.CH,LOCFRSIZE);
WASDIGI := TRUE;
END;
WITH LOCHEAD.CALLS[TOCALLX] DO
FORME := (CALL=ACX.MYCALL.CALL) AND
(SSID=ACX.MYCALL.SSID) AND
(RPTCALL>LASTCALL);
CBYTE := ORD(LOCFRAME.CH[LOCHDSIZE]);
TESTCOM;
IF FRCLASS=OTHERFR THEN
BEGIN { not IFRAME,RR,RNR,REJ,UI }
IF CBYTESP=47 THEN
BEGIN
FRCLASS := SABM;
IF LS=LS1 THEN
BEGIN
NMODEF2 := ACX.CONMODE;
MAKEHEAD(TRUE,LOCHEAD,LASTCALL-1,CONHEAD,CONHDSIZE);
CONCALL := LOCHEAD.CALLS[FRCALLX];
CONCALL.SSID := CHR(ORD(CONCALL.SSID) MOD 16);
END;
END
ELSE IF CBYTESP=67 THEN
FRCLASS := DISC
ELSE IF CBYTESP=15 THEN
FRCLASS := DM
ELSE IF CBYTESP=99 THEN
FRCLASS := UA
ELSE IF CBYTESP=135 THEN
FRCLASS := FRMR;
END;
IF LS<>LS1 {IDLE} THEN
WITH LOCHEAD.CALLS[FRCALLX] DO
ISCONCALL := (CALL=CONCALL.CALL) AND
(SSID=CONCALL.SSID) AND FORME
ELSE
ISCONCALL := FORME;
GETMYFRAME := ISCONCALL;
END { proper AX25 frame };
IF IFDIGI OR (DISPMON AND
( CHKLIST(MON.FRLIST,LOCHEAD.CALLS[FRCALLX]) OR
CHKLIST(MON.TOLIST,LOCHEAD.CALLS[TOCALLX]))) THEN
BEGIN { monitor mode stuff }
DISCALL(LOCHEAD.CALLS[FRCALLX]);
WRITE1('>');
DISCALL(LOCHEAD.CALLS[TOCALLX]);
WRITE1(':');
PUTAO(LOCFRAME.CH,DOFFSET,NDATA);
WRITELAST;
WASMON := TRUE;
END { monitor mode stuff };
END { AX25 protocol };
END { CASE };
END { frame fits };
END { input frame exists };
IF WASDIGI AND (DUMPDIGI IN TRACEDATA.BITS) AND (NOT WASMON) THEN
HEXDUMP(LOCFRAME.CH,LOCFRSIZE,ROEXTVAR.TITLEOUTFR);
IF FORME AND (FRCLASS=SABM) AND
(((LS=LS1) AND NOT ACX.CONOK) OR
((LS<>LS1) AND FORME AND NOT ISCONCALL)) THEN
BEGIN { SABM coming out of the blue from someone else
besides the station I'm connected to OR CONOK reset }
MAKEHEAD(TRUE,LOCHEAD,LASTCALL-1,LOCFRAME.DMRHEAD,I);
MATCH := SHIPSUP(LOCFRAME.DMRHEAD,I,CHR(15){DM},0);
DISPREQ; { show call of station trying to connect }
END;
END { GETMYFRAME };
PROCEDURE CNCDSC(EV:EVTYPE);
{ An event has happened that could affect connect/disconnedt status }
VAR DONE: BOOLEAN;
OLDLS,NEWLS: LSTYPE;
CUREV: EVTYPE;
CURACT: CNCACT;
I,NBYTES: INTEGER;
PROCEDURE VANC_CON(C: CHAR; DORETRY: BOOLEAN);
{ Procedure to send & receive Vancouver connect/disconnect frames }
VAR NBYTES: INTEGER;
BEGIN
NBYTES := 14;
LOCFRAME.FRVAN.FRCALL := ACX.MYCALL.CALL;
LOCFRAME.FRVAN.TOCALL := CONCALL.CALL;
LOCFRAME.FRVAN.VANCTL := C;
LOCFRAME.FRVAN.VANID := CONHEAD.VANCHEAD.VANID;
CALCFC; { calcualte ACX.HOFC }
IF NBYTES<=ACX.HOFC THEN
BEGIN
IF DUMPOFRAME IN TRACEDATA.BITS THEN
BEGIN { show outgoing frame }
HEXDUMP(LOCFRAME.CH,NBYTES,ROEXTVAR.TITLEOUTFR);
END { trace stuff };
PUTHO(LOCFRAME.CH,NBYTES);
END
ELSE
RETRYCNT := RETRYCNT+ORD(DORETRY AND (RETRYCNT>0));
END;
PROCEDURE AX25_CON(C: CHAR; DORETRY: BOOLEAN);
{ Procedure to send AX25 connect/disconnect frames }
BEGIN { AX25_CON }
IF FALSE = SHIPSUP(CONHEAD,CONHDSIZE,C,0) THEN
{ Note: RETRYCNT has been decremented by caller }
RETRYCNT := RETRYCNT+ORD(DORETRY AND (RETRYCNT>0));
END { AX25_CON };
BEGIN { CNCDSC }
IF FALSE = (ACX.T1.RUNNING OR ACX.T1.PENDING) THEN
BEGIN
ACX.T1.RUNNING := FALSE;
ACX.T1.PENDING := TRUE;
ACX.T1.TSTOP := ACX.IFTIME*ROEXTVAR.TICKSPS*CNCCNT;
END;
REPEAT
OFRMRBUF[8] := CHR(ORD(EV));
DONE := TRUE;
OLDLS := LS; { record for possible trace }
CUREV := EV;
CURACT := ROEXTVAR.CNCACTION[LS,EV,ACX.AX25];
CASE CURACT OF
NOP_CNC: ;
UA_S5_CNC:
IF (LS<>LS1) OR ACX.CONOK THEN
BEGIN { event: SABM, state: LS1,LS3,LS5 }
MAKEHEAD(TRUE,LOCHEAD,LASTCALL-1,CONHEAD,CONHDSIZE);
AX25_CON(CHR(99) {UA} ,FALSE);
INTOS5;
END;
DM_CNC:
BEGIN { event: SABM, state: LS4; event: DISC, state: LS1 }
AX25_CON(CHR(15) {DM} ,TRUE); { may report N2EXCEED }
END;
DISC_CNC:
BEGIN { event: T1RO, state: LS4 }
AX25_CON(CHR(67) {DISC} ,TRUE);
END;
UA_CNC:
BEGIN { event: SABM, state: LS2; event: DISC, state: LS4 }
AX25_CON(CHR(99) {UA} ,FALSE);
END;
DM_S1_CNC:
BEGIN { event: DISC, state: LS2 }
AX25_CON(CHR(15) {DM} ,FALSE);
RETRYCNT := XRETRY;
LS := LS1;
END;
UA_S1_CNC:
BEGIN { event: FRMR, state: LS2,LS3,LS5; event: DISC, state: LS5 }
IF (DUMPFRMR IN TRACEDATA.BITS) AND (EV=FRMR) THEN
HEXDUMP(LOCFRAME.CH,LOCFRSIZE,ROEXTVAR.FRMRRCVD);
AX25_CON(CHR(99) {UA} ,FALSE);
RETRYCNT := XRETRY;
LS := LS1;
END;
M_S5_CNC:
INTOS5; { event: UA, state: LS2 }
BAILOUT_CNC:
BEGIN { event: N2EXCEED, state: LS2,LS3,LS4,LS5 OR }
RETRYCNT := XRETRY;
LS := LS1;
IF NMODEF2 OR ACX.MODEF1 OR ACX.MODEF2 THEN
BEGIN
WRITE20(ROEXTVAR.RETRYZERO,20);
WRITELAST;
END;
END;
M_S1_CNC:
BEGIN { event: UA, state: LS4 (AX25);
event: DM, state: LS4
event: DISACK, state: LS4 (AX25) }
RETRYCNT := XRETRY;
LS := LS1;
END;
SABM_CNC:
BEGIN { event: T1RO, state: LS2 }
AX25_CON(CHR(47) {SABM} ,TRUE); { may report event N2EXCEED }
END;
SABM_S2_CNC:
IF (LS<>LS1) OR ACX.CONOK THEN
BEGIN { event: DM,FRMR, state: LS3,LS5;
event: T1RO, state: LS1;
event: UA, state: LS5 }
AX25_CON(CHR(47){SABM},FALSE);
RETRYCNT := XRETRY;
LS := LS2;
END;
FRMR_CNC:
BEGIN { event: T1RO, state: LS3 }
FOR I:=1 TO 8 DO
LOCFRAME.CH[CONHDSIZE+I] := OFRMRBUF[I];
IF SHIPSUP(CONHEAD,CONHDSIZE,CHR(135){FRMR},8) THEN
RETRYCNT := RETRYCNT-ORD(RETRYCNT>0);
END;
CONR_CNC:
BEGIN { event: T1RO, state: LS1,LS2 }
VANC_CON(CHR(23) {CON REQ} ,TRUE);
LS := LS2; { may report event N2EXCEED }
END;
CONA_CNC:
IF (LS<>LS1) OR ACX.CONOK THEN
BEGIN { event: CONREQ, state: LS1,LS2,LS5 }
REMVANID := ORD(LOCFRAME.FRVAN.VANID);
VANC_CON(CHR(7){CON ACK},FALSE);
INTOS5;
END
ELSE IF LS=LS1 THEN
BEGIN { show request for caller }
LOCHEAD.CALLS[FRCALLX].CALL := LOCFRAME.FRVAN.FRCALL;
LOCHEAD.CALLS[TOCALLX].SSID := CHR(0);
DISPREQ;
END;
DISR_CNC:
BEGIN { event: T1RO, state: LS4 }
VANC_CON(CHR(83) {DIS REQ} ,TRUE); { may report event N2EXCEED }
END;
DISA_CNC:
BEGIN { event: DISREQ, state: LS2,LS4,LS5 }
VANC_CON(CHR(67) {DIS ACK} ,FALSE);
RETRYCNT := XRETRY;
LS := LS1;
END;
SAYBUSY_CNC:
BEGIN { event: DM, state: LS2 }
LS := LS1;
WRITE20(ROEXTVAR.CONRQMSG,4); {*** }
DISCALL(CONCALL); { call sign }
WRITE5(ROEXTVAR.BUSYMSG,5); { busy }
WRITELAST;
END;
END { CASE };
IF DUMPSTATE IN TRACEDATA.BITS THEN
BEGIN { show old state, event, action, new state }
WRITE10(ROEXTVAR.STATEMOD,10);
DISINT(ORD(OLDLS));
DISINT(ORD(CUREV));
DISINT(ORD(CURACT));
DISINT(ORD(LS));
WRITELAST;
END { trace code };
IF (LS=LS1) AND (OLDLS<>LS1) THEN
BEGIN
IF (ACX.MODEF1 OR ACX.MODEF2) THEN
BEGIN
WRITE20(ROEXTVAR.CONRQMSG,4);
WRITE15(ROEXTVAR.MSG.DISCON,12);
WRITELAST;
IF ACX.MODEF1 THEN
BEGIN
WRITE5(ROEXTVAR.MSG.PROMPT,4);
END
END;
ACX.RETOUT:=FALSE;
IF ACX.CWID AND ((OLDLS=LS4) OR (OLDLS=LS5)) THEN
CWID;
END;
UNTIL DONE;
I := ORD(LS);
LLRINF(I);
END { CNCDSC };
PROCEDURE SENDFRMR(WXYZ:CHAR;CODENUM:CHAR);
BEGIN { SENDFRMR }
OFRMRBUF[1] := LOCFRAME.CH[LOCHDSIZE];
OFRMRBUF[2] := CHR((NR*16+FLNEXT)*2);
OFRMRBUF[3] := WXYZ;
OFRMRBUF[4] := CODENUM;
OFRMRBUF[5] := CHR(ORD(LS));
OFRMRBUF[6] := CHR(FLFIRST);
OFRMRBUF[7] := CHR(FLCUR);
ACX.T1.RUNNING := FALSE;
ACX.T1.PENDING := FALSE;
RETRYCNT := XRETRY;
IF ACX.AX25 THEN
BEGIN { tell other side }
LS := LS3;
CNCDSC(T1RO);
IF DUMPFRMR IN TRACEDATA.BITS THEN
HEXDUMP(LOCFRAME.CH,CONHDSIZE+9,ROEXTVAR.FRMRSENT);
END
ELSE
BEGIN { don't tell other side, but disconnect }
LS := LS4;
CNCDSC(T1RO);
END;
END { SENDFRMR };
BEGIN { LAPBPROC }
WHILE GETMYFRAME DO
BEGIN { frame for me }
IF DUMPIFRAME IN TRACEDATA.BITS THEN
BEGIN { dump incoming frame, I'm going to use it }
HEXDUMP(LOCFRAME.CH,LOCFRSIZE,ROEXTVAR.TITLEUSFR);
END { dumping incoming frame };
IF (FRCLASS>=SABM) THEN
BEGIN
IF FRCLASS<DISREQ THEN
CNCDSC(FRCLASS)
ELSE
CNCDSC(ROEXTVAR.VANCMAP[FRCLASS])
END
ELSE IF (FRCLASS=OTHERFR) AND (LS>LS1) THEN
SENDFRMR(CHR(1),CHR(1))
ELSE IF LS=LS5 THEN
CASE FRCLASS OF
OTHERFR,T1RO,N2EXCEED: ; { impossible to get here }
RR:
IF ACKFLIGHT(VR) THEN
RCVDRNR := FALSE
ELSE
SENDFRMR(CHR(8),CHR(2));
REJ:
IF ACKFLIGHT(VR) THEN
BEGIN { valid REJ code }
IF ACX. FULLDUP THEN
BEGIN { full duplex code }
{ For the time being, tread REJ like RR when
in full duplex mode. This should get changed
when link level code is added, to abort all
queued up HDLC output. }
{ FLCUR := FLFIRST;
HDLCABORT; }
END
ELSE
BEGIN { half duplex mode }
FLCUR := FLFIRST
END { half duplex mode }
END { valid REJ code }
ELSE
SENDFRMR(CHR(8),CHR(3));
RNR:
IF ACKFLIGHT(VR) THEN
BEGIN { start up timer immediately }
RCVDRNR := TRUE;
ACX.T1.TSTOP := ACX.TICKER+2*ACX.IFTIME*ROEXTVAR.TICKSPS;
ACX.T1.RUNNING := TRUE;
ACX.T1.PENDING := FALSE;
RETRYCNT:=XRETRY;
END
ELSE
SENDFRMR(CHR(8),CHR(4));
IFRAME:
BEGIN
SENDFIN:=(FALSE=(DONTFINL IN TRACEDATA.BITS))
AND PFBIT AND ACX.AX25;
IF VS=NR THEN
BEGIN
CALCFC; { calculate ACX.AOFC }
IF NDATA<=ACX.AOFC THEN
BEGIN
IF WASMON=FALSE THEN { dont show info twice if monitored }
PUTAO(LOCFRAME.CH,DOFFSET,NDATA);
NR := SUCC(ORD(NR)) MOD 8;
SENDRR := TRUE;
ACX.DCDDRP := FALSE;
END
ELSE
BEGIN
SENDRNR := TRUE;
ACX.DCDDRP := FALSE;
END
END
ELSE
BEGIN
SENDREJ := ACX.AX25;
SENDRR := TRUE;
ACX.DCDDRP := FALSE;
RNRSIZE := NDATA;
END;
IF FALSE = ACKFLIGHT(VR) THEN
SENDFRMR(CHR(8),CHR(5));
END;
END { CASE };
END { frame for me };
IF ACX.T1.RUNNING THEN
BEGIN
TICKTEMP := ACX.TICKER-ACX.T1.TSTOP; { will overflow }
IF TICKTEMP>0 THEN
BEGIN
ACX.T1.RUNNING := FALSE;
ACX.T1.PENDING := FALSE;
ACX.RETOUT := LS<>LS1;
IF LS<>LS1 THEN
BEGIN
IF RETRYCNT=0 THEN
CNCDSC(N2EXCEED)
ELSE
BEGIN
IF LS<>LS5 THEN
BEGIN
RETRYCNT := RETRYCNT-ORD(RETRYCNT>0);
CNCDSC(T1RO);
END
ELSE
IF FALSE=RETRY_SIP THEN
BEGIN { resend all I frames outstanding, forget RNR received }
RCVDRNR := FALSE;
FLCUR := FLFIRST;
RETRY_SIP := FLCUR<>FLNEXT;
RETRY_SEQ:=FLNEXT {RETRY FINISH POINT};
RETRYCNT := RETRYCNT-ORD(RETRYCNT>0);
END
END
END;
END;
END;
IF ACX.TBEACON.RUNNING THEN
BEGIN
TICKTEMP := ACX.TICKER-ACX.TBEACON.TSTOP; { will overflow }
IF TICKTEMP>0 THEN
BEGIN { time to do beacon }
ACX.TBEACON.RUNNING := (ACX.BECTIM<>0) AND ACX.BECEVY;
ACX.TBEACON.TSTOP := ACX.TICKER+ROEXTVAR.TICKSPS*ACX.BECTIM*10;
SHIPUI(FALSE);
END;
END { beacon stuff };
IF LS=LS1 THEN
BEGIN { test for data input; it becomes UI frame }
WRAPAI(ACX.AIRP,LOCFRSIZE,LOCHDSIZE);
IF LOCFRSIZE<>0 THEN
SHIPUI(TRUE);
END { test for data becoming UI frames };
IF LS=LS5 THEN
BEGIN
IF (NOT ACX.DCD) OR ACX.DCDDRP OR ACX.FULLDUP THEN
BEGIN
NRCALC:=(NR*2+ORD(SENDFIN))*16;
IF RNRSIZE<>0 THEN
BEGIN
CALCFC;
SENDRR := ACX.AOFC>=RNRSIZE;
END;
IF SENDRNR THEN
BEGIN
IF SHIPSUP(CONHEAD,CONHDSIZE,CHR(NRCALC+5 {RNR} ),0) THEN
BEGIN
SENDRNR := FALSE;
SENDREJ := FALSE;
SENDRR := FALSE; SENDFIN:=FALSE;
END
END
ELSE IF SENDREJ THEN
BEGIN
IF SHIPSUP(CONHEAD,CONHDSIZE,CHR(NRCALC+9 {REJ} ),0) THEN
BEGIN
SENDREJ := FALSE;
SENDRR := FALSE; SENDFIN:=FALSE;
END
END;
IF FALSE = (RCVDRNR OR SENDFIN) THEN
BEGIN
IF SHIPOUT THEN
SENDRR := FALSE;
END;
IF SENDRR OR SENDFIN THEN
IF SHIPSUP(CONHEAD,CONHDSIZE,CHR(NRCALC+1{RR}),0) THEN
BEGIN
RNRSIZE:=0;
SENDRR := FALSE ; SENDFIN:=FALSE;
END;
END { DCD drop sturr };
END { LS=LS5 };
CASE COMEV OF
F_NULL: ;
F_CON: { connect command }
IF LS=LS1 THEN
BEGIN { start everything with T1RO }
MAKEHEAD(FALSE,CNCCALL,CNCCNT,CONHEAD,CONHDSIZE);
CONCALL := CNCCALL.CALLS[FRCALLX];
ACX.T1.RUNNING := FALSE;
ACX.T1.PENDING := FALSE;
LS := LS2; { kludge to avoid CONOK test }
RETRYCNT := XRETRY;
CNCDSC(T1RO);
END;
F_DISC:
BEGIN { disconnect command }
IF LS=LS5 THEN
BEGIN
LS := LS4;
RETRYCNT := XRETRY;
CNCDSC(T1RO);
END
ELSE
CNCDSC(N2EXCEED);
END;
END { CASE };
{ Finally, check to see if no HDLC output is in progress
and timer T1 has its pending bit set.
If these conditions are satisfied, then start timer T1 }
IF (FALSE = ACX.T1.RUNNING) AND ACX.T1.PENDING AND (FALSE = ACX.HACT) THEN
BEGIN { the time has come to start the timer, T1.TSTOP has interval }
ACX.T1.RUNNING:=TRUE;
ACX.T1.PENDING:=FALSE;
ACX.T1.TSTOP := ACX.TICKER+ACX.T1.TSTOP;
END;
END { LAPBPROC };
FUNCTION COMPARSE: FTYPE;
VAR
BUF: BUFTYPE;
ARS: INTEGER;
POINT: 1..BUFRSIZE { pointer into buffer };
PPOINT: INTEGER;
PNUM,I,TC: INTEGER;
TYPTOKEN: (NOTOKEN,ALFTOKEN,NUMTOKEN,HEXTOKEN,ERRTOKEN);
TOKEN: CH8;
CTYPE: COM_TYPE;
LTYPE: LIT_TYPE;
LOOKING,MATCH,GOODVAL: BOOLEAN;
OK: BOOLEAN;
EH: BOOLEAN;
TBIT: BOOLEAN;
KLUDGE: HEADCALL;
W8FIX: CH8; { kludge to avoid compiler problem }
CMPRS: FTYPE;
FUNCTION SP_SKIP(I: INTEGER): BOOLEAN;
VAR LOOPING: BOOLEAN;
BEGIN { SP_SKIP }
LOOPING := TRUE;
POINT := I;
WHILE LOOPING DO
BEGIN
IF POINT >ARS THEN
LOOPING := FALSE
ELSE IF BUF[POINT]=' ' THEN
POINT := POINT+1
ELSE
LOOPING := FALSE;
END { do while looping };
SP_SKIP := POINT<=ARS;
END { SP_SKIP };
FUNCTION UPPER(C: CHAR): CHAR;
BEGIN
IF (C >= 'a') AND (C <= 'z') THEN
UPPER := CHR(ORD(C)-ORD('a')+ORD('A'))
ELSE
UPPER := C;
END;
PROCEDURE PTOKEN(NPOINT:INTEGER);
VAR I: 0..255;
C: CHAR;
LOOPING: BOOLEAN;
BEGIN { TOKEN }
FOR I := 1 TO 8 DO
TOKEN[I] := ' ';
LOOPING := SP_SKIP(NPOINT);
PPOINT := POINT;
PNUM := 0;
TC := 0;
TYPTOKEN := NOTOKEN;
IF LOOPING THEN
BEGIN
C := UPPER(BUF[POINT]);
IF ((C >='A' ) AND (C <= 'Z')) OR ((C >= '0') AND (C <= '9')) THEN
BEGIN
TYPTOKEN := NUMTOKEN;
WHILE LOOPING DO
BEGIN
TC := TC+1;
IF TC<9 THEN
TOKEN[TC] := C;
IF (TYPTOKEN = NUMTOKEN) AND(C >= '0') AND (C <= '9') THEN
PNUM := 10*PNUM+ORD(C)-ORD('0')
ELSE
TYPTOKEN := ALFTOKEN;
POINT := POINT+1;
IF POINT<=ARS THEN
BEGIN
C := UPPER(BUF[POINT]);
LOOPING := ((C >='A' ) AND (C <= 'Z')) OR ((C >= '0')
AND (C <= '9')) ;
END
ELSE
LOOPING := FALSE;
END { looping on name };
IF TC > 8 THEN
TC := 8;
END { alfanumeric token }
ELSE IF BUF[POINT] = '$' THEN
BEGIN
POINT := POINT + 1;
TYPTOKEN := HEXTOKEN;
LOOPING := POINT <= ARS;
IF LOOPING = FALSE THEN
TYPTOKEN := ERRTOKEN;
WHILE LOOPING DO
BEGIN
C := UPPER(BUF[POINT]);
IF (C >= '0') AND (C <= '9') THEN
PNUM := 16*PNUM+ORD(C)-ORD('0')
ELSE IF (C >= 'A') AND (C <= 'F') THEN
PNUM := 16*PNUM+ORD(C)-ORD('A')+10
ELSE IF C <> ' ' THEN
BEGIN
LOOPING := FALSE;
TYPTOKEN := ERRTOKEN;
END;
POINT := POINT+1;
IF POINT > ARS THEN
LOOPING := FALSE;
END { looping }
END { hex token }
ELSE IF POINT <= ARS THEN
TYPTOKEN := ERRTOKEN
END; { looping on find token }
END { PTOKEN };
PROCEDURE DOCALL(VAR C: HEADCALL);
{ PTOKEN has already been called. Anything but an
ALFTOKEN is an error. }
VAR I: 0..255;
BEGIN
IF (TYPTOKEN <> ALFTOKEN) OR (TC > 6) THEN
OK := FALSE
ELSE
BEGIN
FOR I := 1 TO 6 DO
C.CALL[I] := ' '; { blank it }
C.SSID := CHR(0);
FOR I := 1 TO TC DO
C.CALL[I] := TOKEN[I];
IF (POINT <= ARS) AND (BUF[POINT] = '-') THEN
BEGIN
POINT := POINT+1;
PTOKEN(POINT);
IF TYPTOKEN <> NUMTOKEN THEN
OK := FALSE
ELSE IF PNUM > 15 THEN
OK := FALSE
ELSE
C.SSID := CHR(PNUM);
END;
END;
END { DOCALL };
PROCEDURE DOCLIST(VAR CARRAY: HEADTYPE; START: INTEGER; VAR I: INTEGER);
{ PTOKEN has not been called. Gets a list of call signs, separated
by commas. Return OK=FALSE if bad callsign encountered. Count of
calls placed in CARRAY is returned in I. }
VAR LOOPING: BOOLEAN;
BEGIN
OK := TRUE;
I := START;
LOOPING := TRUE;
WHILE (I <= NUMHDCALL) AND OK AND LOOPING DO
BEGIN
PTOKEN(POINT);
IF TYPTOKEN<>ALFTOKEN THEN
OK := FALSE
ELSE IF OK THEN
BEGIN
DOCALL(KLUDGE);
CARRAY.CALLS[I] := KLUDGE;
I := I + 1;
IF (POINT <= ARS) AND (I <= NUMHDCALL) THEN
BEGIN
LOOPING := BUF[POINT] = ',';
POINT := POINT + 1;
END
ELSE
LOOPING := FALSE;
END;
END; { while looping }
I := I - START;
END; { DOCLIST }
PROCEDURE PLIT;
VAR MATCH: BOOLEAN;
LOOKING: BOOLEAN;
I: 0..255;
BEGIN
LOOKING := TRUE;
LTYPE := SUCC(L_FNULL);
WHILE (LTYPE<L_LNULL) AND LOOKING DO
BEGIN
MATCH := TRUE;
I := 1;
WHILE (I <= TC) AND MATCH DO
BEGIN
MATCH := TOKEN[I] = ROEXTVAR.LITTEXT[ORD(LTYPE),I];
I := I + 1;
END;
IF MATCH THEN
LOOKING := FALSE
ELSE
LTYPE := SUCC(LTYPE);
END;
IF LTYPE = L_YES THEN
LTYPE := L_ON
ELSE IF LTYPE = L_NO THEN
LTYPE := L_OFF;
END;
PROCEDURE PCOM;
VAR MATCH: BOOLEAN;
LOOKING: BOOLEAN;
I: 0..255;
BEGIN
LOOKING := TRUE;
CTYPE := SUCC(C_FNULL);
WHILE (CTYPE<C_LNULL) AND LOOKING DO
BEGIN
MATCH := TRUE;
I := 1;
WHILE (I <= TC) AND MATCH DO
BEGIN
MATCH := TOKEN[I] = ROEXTVAR.COMTEXT[ORD(CTYPE),I];
I := I + 1;
END;
IF MATCH THEN
LOOKING := FALSE
ELSE
CTYPE := SUCC(CTYPE);
END;
END;
PROCEDURE WRITEDOL(I: INTEGER);
VAR J: INTEGER;
BEGIN
I := I + PROMPTLEN-1;
FOR J:=1 TO I DO
WRITEBLK;
WRITE1('$');
WRITELAST;
END;
PROCEDURE WRITEEH(I: INTEGER);
BEGIN
WRITEDOL(I);
WRITE5(ROEXTVAR.MSG.EH,3);
WRITELAST;
END;
PROCEDURE DISBOOL(BIT: BOOLEAN);
BEGIN
IF BIT THEN
WRITE5(ROEXTVAR.MSG.ON,3)
ELSE
WRITE5(ROEXTVAR.MSG.OFF,4)
END;
PROCEDURE SETBOOL(VAR BIT: BOOLEAN);
BEGIN { SETBOOL }
PTOKEN(POINT);
IF TYPTOKEN <> ALFTOKEN THEN
OK := FALSE
ELSE
BEGIN
PLIT;
IF LTYPE = L_ON THEN
BEGIN
PTOKEN(POINT);
IF TYPTOKEN <> NOTOKEN THEN
OK := FALSE
ELSE
BEGIN
WRITE5(ROEXTVAR.MSG.WAS,4);
DISBOOL(BIT);
WRITELAST;
BIT := TRUE;
END
END
ELSE IF LTYPE <> L_OFF THEN
OK := FALSE
ELSE
BEGIN
PTOKEN(POINT);
IF TYPTOKEN <> NOTOKEN THEN
OK := FALSE
ELSE
BEGIN
WRITE5(ROEXTVAR.MSG.WAS,4);
DISBOOL(BIT);
WRITELAST;
BIT := FALSE;
END
END;
END;
IF FALSE = OK THEN
WRITEEH(PPOINT);
END; { SETBOOL }
PROCEDURE SETINT(VAR INT: INTEGER; LOW,HIGH: INTEGER);
VAR TI: INTEGER;
BEGIN
PTOKEN(POINT);
IF (TYPTOKEN <> NUMTOKEN) AND (TYPTOKEN <> HEXTOKEN) THEN
OK := FALSE
ELSE IF (PNUM < LOW) OR (PNUM > HIGH) THEN
BEGIN
WRITEDOL(PPOINT);
WRITE20(ROEXTVAR.MSG.VALUEOUT,18);
WRITELAST;
END
ELSE
BEGIN
TI := PNUM;
PTOKEN(POINT);
IF TYPTOKEN <> NOTOKEN THEN
OK := FALSE
ELSE
BEGIN
WRITE5(ROEXTVAR.MSG.WAS,4);
DISINT(INT);
WRITELAST;
INT := TI;
END
END;
IF FALSE = OK THEN
WRITEEH(PPOINT);
END { SETINT };
PROCEDURE SETHEX(VAR INT: INTEGER; LOW,HIGH: INTEGER);
VAR TI: INTEGER;
BEGIN
PTOKEN(POINT);
IF (TYPTOKEN <> NUMTOKEN) AND (TYPTOKEN <> HEXTOKEN) THEN
OK := FALSE
ELSE IF (PNUM < LOW) OR (PNUM > HIGH) THEN
BEGIN
WRITEDOL(PPOINT);
WRITE20(ROEXTVAR.MSG.VALUEOUT,18);
WRITELAST;
END
ELSE
BEGIN
TI := PNUM;
PTOKEN(POINT);
IF TYPTOKEN <> NOTOKEN THEN
OK := FALSE
ELSE
BEGIN
WRITE5(ROEXTVAR.MSG.WAS,4);
DISHEX(INT);
WRITELAST;
INT := TI;
END
END;
IF FALSE = OK THEN
WRITEEH(PPOINT);
END { SETHEX };
PROCEDURE SETCHR(VAR CH: CHAR; LOW,HIGH: INTEGER);
VAR TI: INTEGER;
BEGIN
PTOKEN(POINT);
IF (TYPTOKEN <> NUMTOKEN) AND (TYPTOKEN <> HEXTOKEN) THEN
OK := FALSE
ELSE IF (PNUM < LOW) OR (PNUM > HIGH) THEN
BEGIN
WRITEDOL(PPOINT);
WRITE20(ROEXTVAR.MSG.VALUEOUT,18);
WRITELAST;
END
ELSE
BEGIN
TI := PNUM;
PTOKEN(POINT);
IF TYPTOKEN <> NOTOKEN THEN
OK := FALSE
ELSE
BEGIN
WRITE5(ROEXTVAR.MSG.WAS,4);
DISCHR(CH);
WRITELAST;
CH := CHR(TI);
END
END;
IF FALSE = OK THEN
WRITEEH(PPOINT);
END;
FUNCTION ACTIONCOM(ACT: COM_TYPE): BOOLEAN;
{ This routine exists because HP Pascal doesn't like sets much }
BEGIN
ACTIONCOM := (C_PERM = ACT) OR
(C_DISCONNE = ACT) OR
(C_DISPLAY = ACT ) OR
(C_ID = ACT) OR
(C_TRANS = ACT) OR
(C_RESET = ACT) OR
(C_CALIBRAT = ACT) OR
(C_PROGRAM = ACT) OR
(C_CONVERS = ACT);
END;
PROCEDURE DISPLAY(I: COM_TYPE);
BEGIN
IF ACTIONCOM(I) = FALSE THEN
BEGIN
IF (I <> C_CONNECT) THEN
WRITE8(ROEXTVAR.COMTEXT[ORD(I)],8);
CASE I OF
C_LNULL: ;
C_ABAUD: DISINT (ROEXTVAR.ABAUD[ACX.ABAUD]);
C_ABIT: DISINT (ACX.ABIT);
C_AUTOLF: DISBOOL (ACX.AUTOLF);
C_AWLEN: DISINT (ACX.AWLEN);
C_AX25: DISBOOL (ACX.AX25);
C_AXDELAY: DISINT (ACX.AXDLY);
C_AXHANG: DISINT (ACX.AXHANG);
C_BEACON:
BEGIN
IF ACX.BECEVY THEN
WRITE8(ROEXTVAR.LITTEXT[ORD(L_EVERY)],6)
ELSE
WRITE8(ROEXTVAR.LITTEXT[ORD(L_AFTER)],6);
WRITEINT(ACX.BECTIM);
END;
C_BKONDEL: DISBOOL (ACX.BKONDEL);
C_BTEXT:
BEGIN
IF ACX.BECLEN > 0 THEN WRITE128(ACY.BECTXT,ACX.BECLEN-1);
END;
C_CALIBRAT: ;
C_CANLINE: DISCHR (ACX.CLCHR);
C_CANPAC: DISCHR (ACX.CPCHR);
C_CMDTIME: DISINT (ACX.CMTIME);
C_COMMAND: DISCHR (ACX.CMDCHR);
C_CONMODE:
IF ACX.CONMODE THEN
WRITE8(ROEXTVAR.LITTEXT[ORD(L_CONVERS)],7)
ELSE
WRITE8(ROEXTVAR.LITTEXT[ORD(L_TRANS)],5);
C_CONNECT:
BEGIN
WRITE15(ROEXTVAR.MSG.LINKSTATE,15);
CASE LS OF
LS1: WRITE15(ROEXTVAR.MSG.DISCON,12);
LS2: WRITE20(ROEXTVAR.MSG.CONINPROG,19);
LS3: WRITE20(ROEXTVAR.MSG.FRMRINPROG,16);
LS4: WRITE20(ROEXTVAR.MSG.DISCINPROG,16);
LS5:
BEGIN
WRITE15(ROEXTVAR.MSG.CONTO,13);
DISCALL(CONCALL);
IF CNCCNT>1 THEN
BEGIN
WRITEBLK;
WRITE8(ROEXTVAR.LITTEXT[ORD(L_VIA)],4);
DISCLIST(CNCCALL, RPCALLX, CNCCNT-1);
END;
END;
END { CASE LS };
END { C_CONNECT };
C_CONOK: DISBOOL (ACX.CONOK);
C_CONVERS: ;
C_CPACTIME: DISBOOL (ACX.CPT);
C_CR: DISBOOL (ACX.CR);
C_CWID: DISBOOL (ACX.CWID);
C_DEBUG: DISCHR (ACX.DBGCHR);
C_DELETE: DISBOOL (ACX.DELCHR);
C_DIGIPEAT: DISBOOL (ACX.RPTOK);
C_DISCONNE: ;
C_DISPLAY: ;
C_DWAIT: DISINT (ACX.DWAIT);
C_ECHO: DISBOOL (ACX.ECHO);
C_ESCAPE: DISBOOL (ACX.ESCAPE);
C_FLOW: DISBOOL (ACX.FLOW);
C_FRACK: DISINT (ACX.IFTIME);
C_FULLDUP: DISBOOL (ACX.FULLDUP);
C_HBAUD: DISINT (ROEXTVAR.HBAUD[ACX.HBAUD]);
C_ID: ;
C_IDTEXT:
BEGIN
IF ACX.IDLEN > 0 THEN WRITE128(ACY.IDTXT,ACX.IDLEN-1);
END;
C_LCOK: DISBOOL (ACX.LCOK);
C_LFADD: DISBOOL (ACX.LFADD);
C_MAXFRAME: DISINT (ACX.KMAX);
C_MONITOR: DISBOOL (ACX.MONON);
C_MONALL: DISBOOL (ACX.MONALL);
C_MONCON: DISBOOL (ACX.MONCON);
C_MONTO:
IF MON.TOLIST.CNT = 0 THEN
IF MON.TOLIST.ALL THEN
WRITE8(ROEXTVAR.LITTEXT[ORD(L_ALL)],3)
ELSE
WRITE8(ROEXTVAR.LITTEXT[ORD(L_NONE)],4)
ELSE
DISCLIST(MON.TOLIST.CALLS,1,MON.TOLIST.CNT);
C_MONFROM:
IF MON.FRLIST.CNT = 0 THEN
IF MON.FRLIST.ALL THEN
WRITE8(ROEXTVAR.LITTEXT[ORD(L_ALL)],3)
ELSE
WRITE8(ROEXTVAR.LITTEXT[ORD(L_NONE)],4)
ELSE
DISCLIST(MON.FRLIST.CALLS, 1, MON.FRLIST.CNT);
C_MYCALL: DISCALL(ACX.MYCALL);
C_MYVADR: DISCHR (ACX.VANID);
C_NULLS: DISINT (ACX.NULLS);
C_NUCR: DISBOOL (ACX.NUCR);
C_NULF: DISBOOL (ACX.NULF);
C_PACLEN: DISINT (ACX.PLEN);
C_PACTIME:
BEGIN
IF ACX.PCEVY THEN
WRITE8(ROEXTVAR.LITTEXT[ORD(L_EVERY)],6)
ELSE
WRITE8(ROEXTVAR.LITTEXT[ORD(L_AFTER)],6);
DISINT (ACX.PCTIME);
END;
C_PARITY: DISINT (ACX.PARITY);
C_PASS: DISCHR (ACX.PASCHR);
C_PERM: ;
C_PROGRAM: ;
C_RETRY: DISINT (ACX.RETRY);
C_REDISP: DISCHR (ACX.RDSCHR);
C_RESET: ;
C_SCREENL: DISINT (ACX.SCWID);
C_SENDPAC: DISCHR (ACX.SPCHR);
C_START: DISCHR (ACX.STRCHR);
C_STOP: DISCHR (ACX.STPCHR);
C_TRACE: DISHEX (TRACEDATA.NUMBR);
C_TRANS: ;
C_TXDELAY: DISINT (ACX.TXDLY);
C_TXFLOW: DISBOOL (ACX.TXF);
C_UNPROTO:
BEGIN
IF UCONLST.CALLS[FRCALLX].CALL[1] <> ' ' THEN
DISCALL(UCONLST.CALLS[FRCALLX])
ELSE
WRITE8(ROEXTVAR.LITTEXT[ORD(L_NONE)],5);
IF ACX.UCONCNT>1 THEN
BEGIN
WRITEBLK;
WRITE8(ROEXTVAR.LITTEXT[ORD(L_VIA)],4);
DISCLIST(UCONLST, RPCALLX, ACX.UCONCNT-1);
END;
END;
C_VRPT: DISBOOL (ACX.VRPT);
C_VDIGIPEA: DISBOOL (ACX.VANCDP);
C_XFLOW: DISBOOL (ACX.XFLOW);
C_XMITOK: DISBOOL (ACX.XMITOK);
C_XOFF: DISCHR (ACX.XFFCHR);
C_XON: DISCHR (ACX.XONCHR);
END { CASE on CTYPE };
WRITELAST;
END;
END;
PROCEDURE PCLIST(VAR L: MONLIST);
{ parse MONFROM and MONTO commands }
VAR SV: INTEGER;
BEGIN
SV := POINT;
PTOKEN(POINT);
OK := TRUE;
IF TYPTOKEN <> ALFTOKEN THEN
OK := FALSE
ELSE
BEGIN
PLIT;
IF LTYPE = L_ALL THEN
BEGIN
L.ALL := TRUE;
L.CNT := 0;
END
ELSE IF LTYPE = L_NONE THEN
BEGIN
L.ALL := FALSE;
L.CNT := 0;
END
ELSE
BEGIN
POINT := SV;
DOCLIST(L.CALLS, 1, SV);
L.CNT := SV;
END
END;
END;
PROCEDURE EVRYAFTR(VAR EVAF: BOOLEAN; VAR EATIME: INTEGER; MAXT: INTEGER);
BEGIN { EVRYAFTR }
TBIT := EVAF;
PTOKEN(POINT);
IF TYPTOKEN = ALFTOKEN THEN
BEGIN
PLIT;
IF (LTYPE <> L_EVERY) AND (LTYPE <> L_AFTER) THEN
OK := FALSE
ELSE
BEGIN
EVAF := TRUE;
IF LTYPE = L_AFTER THEN
EVAF := FALSE;
PTOKEN(POINT);
END;
END;
IF (TYPTOKEN <> NUMTOKEN) AND (TYPTOKEN <> HEXTOKEN) THEN
OK := FALSE;
IF OK THEN
IF PNUM > MAXT THEN
BEGIN
WRITEDOL(PPOINT);
WRITE20(ROEXTVAR.MSG.VALUEOUT,20);
WRITELAST;
END
ELSE
BEGIN
WRITE5(ROEXTVAR.MSG.WAS,4);
IF TBIT THEN
WRITE8(ROEXTVAR.LITTEXT[ORD(L_EVERY)],6)
ELSE
WRITE8(ROEXTVAR.LITTEXT[ORD(L_AFTER)],6);
WRITEINT(EATIME);
WRITELAST;
EATIME := PNUM;
END
END; { EVRYAFTR }
PROCEDURE GETTXT(VAR TEXT: CH128; VAR LENGTH: INTEGER);
BEGIN
WRITE5(ROEXTVAR.MSG.WAS,4);
IF LENGTH > 0 THEN WRITE128(TEXT,LENGTH)
ELSE WRITELAST;
I := 1;
WHILE ((POINT <= ARS) AND (I < 128)) DO
BEGIN
TEXT[I] := BUF[POINT];
POINT := POINT + 1;
I := I + 1;
END;
LENGTH := I;
TEXT[I] := CHR(13);
END;
PROCEDURE SETBAUD(VAR INT:INTEGER; BAUD:BAUDTYPE);
VAR I: INTEGER;
BEGIN
PTOKEN(POINT);
IF (TYPTOKEN <> NUMTOKEN) AND (TYPTOKEN <> HEXTOKEN) THEN
OK := FALSE
ELSE
BEGIN
I := 0;
WHILE ((PNUM <> BAUD[I]) AND (I < 16)) DO
I := I+1;
IF I = 16 THEN
OK := FALSE
ELSE
BEGIN
WRITE5(ROEXTVAR.MSG.WAS,4);
DISINT(BAUD[INT]);
WRITELAST;
INT := I;
END
END;
IF OK = FALSE THEN
WRITEEH(PPOINT);
END;
PROCEDURE DO_DISPLAY;
VAR CC: COM_TYPE;
BEGIN
PTOKEN(POINT);
IF TYPTOKEN = NOTOKEN THEN
BEGIN
FOR CC := SUCC(C_FNULL) TO PRED(C_LNULL) DO
DISPLAY(CC);
END
ELSE IF TYPTOKEN = ALFTOKEN THEN
BEGIN
PLIT;
IF LTYPE = L_LINK THEN
BEGIN
DISPLAY(C_AX25);
DISPLAY(C_CONMODE);
DISPLAY(C_CONOK);
DISPLAY(C_CR);
DISPLAY(C_DIGIPEAT);
DISPLAY(C_FULLDUP);
DISPLAY(C_HBAUD);
DISPLAY(C_LFADD);
DISPLAY(C_MAXFRAME);
DISPLAY(C_PACLEN);
DISPLAY(C_RETRY);
DISPLAY(C_TRACE);
DISPLAY(C_VDIGIPEA);
DISPLAY(C_VRPT);
DISPLAY(C_XMITOK);
END
ELSE IF LTYPE = L_ID THEN
BEGIN
DISPLAY(C_BEACON);
DISPLAY(C_BTEXT);
DISPLAY(C_CWID);
DISPLAY(C_IDTEXT);
DISPLAY(C_MYCALL);
DISPLAY(C_MYVADR);
DISPLAY(C_UNPROTO);
END
ELSE IF LTYPE = L_MONITOR THEN
BEGIN
DISPLAY(C_MONITOR);
DISPLAY(C_MONALL);
DISPLAY(C_MONCON);
DISPLAY(C_MONFROM);
DISPLAY(C_MONTO);
END
ELSE IF LTYPE = L_TERMINAL THEN
BEGIN
DISPLAY(C_ABAUD);
DISPLAY(C_ABIT);
DISPLAY(C_AUTOLF);
DISPLAY(C_AWLEN);
DISPLAY(C_BKONDEL);
DISPLAY(C_ECHO);
DISPLAY(C_ESCAPE);
DISPLAY(C_FLOW);
DISPLAY(C_LCOK);
DISPLAY(C_NULLS);
DISPLAY(C_NUCR);
DISPLAY(C_NULF);
DISPLAY(C_PARITY);
DISPLAY(C_SCREENL);
DISPLAY(C_TXFLOW);
DISPLAY(C_XFLOW);
END
ELSE IF LTYPE = L_TIMING THEN
BEGIN
DISPLAY(C_AXDELAY);
DISPLAY(C_AXHANG);
DISPLAY(C_CMDTIME);
DISPLAY(C_CPACTIME);
DISPLAY(C_DWAIT);
DISPLAY(C_FRACK);
DISPLAY(C_PACTIME);
DISPLAY(C_TXDELAY);
END
ELSE IF LTYPE = L_CHAR THEN
BEGIN
DISPLAY(C_CANLINE);
DISPLAY(C_CANPAC);
DISPLAY(C_COMMAND);
DISPLAY(C_DEBUG);
DISPLAY(C_DELETE);
DISPLAY(C_PASS);
DISPLAY(C_REDISP);
DISPLAY(C_SENDPAC);
DISPLAY(C_START);
DISPLAY(C_STOP);
DISPLAY(C_XON);
DISPLAY(C_XOFF);
END
ELSE OK := FALSE;
END
ELSE OK := FALSE;
IF OK = FALSE THEN WRITEEH(PPOINT);
END; { add more code here /*N*/ }
PROCEDURE DOIT;
VAR
CCTYPE: COM_TYPE;
II: INTEGER;
BEGIN
CASE CTYPE OF
C_LNULL:
BEGIN
OK := FALSE;
EH := TRUE;
END;
C_ABAUD: SETBAUD (ACX.ABAUD,ROEXTVAR.ABAUD);
C_ABIT: SETINT (ACX.ABIT,1,2);
C_AUTOLF: SETBOOL (ACX.AUTOLF);
C_AWLEN: SETINT(ACX.AWLEN,7,8);
C_AX25:
BEGIN
IF LS <> LS1 THEN
BEGIN
WRITE20(ROEXTVAR.MSG.NOTWHILE,19);
WRITELAST;
OK := FALSE;
END
ELSE
SETBOOL(ACX.AX25);
END;
C_AXDELAY: SETINT (ACX.AXDLY,0,15);
C_AXHANG: SETINT (ACX.AXHANG,0,15);
C_BEACON:
BEGIN { BEACON }
EVRYAFTR(ACX.BECEVY,ACX.BECTIM,255);
IF OK THEN
BEGIN
{ Now see if we are (re)starting the clock, or stopping it. }
IF ACX.BECTIM = 0 THEN
ACX.TBEACON.RUNNING := FALSE
ELSE
BEGIN
ACX.TBEACON.RUNNING := TRUE;
ACX.TBEACON.TSTOP :=
ACX.TICKER + ACX.BECTIM*ROEXTVAR.TICKSPS*10;
END;
END
ELSE
EH := TRUE;
END; { BEACON }
C_BKONDEL: SETBOOL(ACX.BKONDEL);
C_BTEXT: GETTXT(ACY.BECTXT,ACX.BECLEN);
C_CALIBRAT: CALIBR;
C_CANLINE: SETCHR (ACX.CLCHR,0,127);
C_CANPAC: SETCHR (ACX.CPCHR,0,127);
C_CMDTIME: SETINT(ACX.CMTIME,0,15);
C_COMMAND: SETCHR (ACX.CMDCHR,0,127);
C_CONMODE:
BEGIN { CONMODE }
PTOKEN(POINT);
IF TYPTOKEN <> ALFTOKEN THEN
BEGIN
OK := FALSE;
EH := TRUE;
END
ELSE
BEGIN { alpha }
PLIT;
TBIT := ACX.CONMODE;
IF (LTYPE <> L_CONVERS) AND (LTYPE <> L_TRANS) THEN
BEGIN
OK := FALSE;
EH := TRUE;
END
ELSE
BEGIN
ACX.CONMODE := TRUE;
IF LTYPE = L_TRANS THEN
ACX.CONMODE := FALSE;
WRITE5(ROEXTVAR.MSG.WAS,4);
IF TBIT THEN
WRITE8(ROEXTVAR.LITTEXT[ORD(L_CONVERS)],7)
ELSE
WRITE8(ROEXTVAR.LITTEXT[ORD(L_TRANS)],5);
WRITELAST;
END;
END; { alpha }
END; { CONMODE }
C_CONNECT:
IF LS <> LS1 THEN
BEGIN
WRITE15(ROEXTVAR.MSG.CANTCON,15);
DISPLAY(C_CONNECT);
OK := FALSE;
END
ELSE
BEGIN { LS=LS1 }
CNCCNT := 1;
NMODEF2 := ACX.CONMODE;
PTOKEN(POINT); { Get first token after command keyword }
DOCALL(KLUDGE); { Get first callsign }
{ Yes, I am really putting the evenrual 'TO' call in the array
with an index of FRCALLX. What I'm really doing is building
a pseudo incoming SABM frame for Dave's code. I'm told that
this makes things easy for him. }
IF OK THEN
BEGIN { tocall ok }
CNCCALL.CALLS[FRCALLX] := KLUDGE;
PTOKEN(POINT); { next token }
IF TYPTOKEN=ALFTOKEN THEN
PLIT
ELSE IF TYPTOKEN <> NOTOKEN THEN
OK := FALSE;
END; { tocall ok }
IF OK AND (TYPTOKEN=ALFTOKEN) THEN
IF LTYPE = L_VIA THEN
BEGIN { parse digipeaters }
DOCLIST(CNCCALL,RPCALLX,I);
IF OK THEN
BEGIN
CNCCNT := I+1;
PTOKEN(POINT); { setup next token }
IF TYPTOKEN = ALFTOKEN THEN
PLIT
ELSE IF TYPTOKEN <> NOTOKEN THEN
OK := FALSE;
END;
END; { digipeaters }
IF OK AND (TYPTOKEN = ALFTOKEN) THEN
IF LTYPE = L_CONVERS THEN
NMODEF2 := TRUE
ELSE IF LTYPE = L_TRANS THEN
NMODEF2 := FALSE
ELSE
OK := FALSE;
IF FALSE = OK THEN
EH := TRUE
ELSE
CMPRS := F_CON;
END; { LS = LS1 }
{ end CONNECT }
C_CONOK: SETBOOL (ACX.CONOK);
C_CONVERS:
BEGIN
ACX.MODEF2 := TRUE;
ACX.MODEF1 := FALSE;
SETMOD; { tell LLR - mode change }
END;
C_CPACTIME: SETBOOL (ACX.CPT);
C_CR: SETBOOL (ACX.CR);
C_CWID: SETBOOL (ACX.CWID);
C_DEBUG: SETCHR (ACX.DBGCHR,0,127);
C_DELETE: SETBOOL (ACX.DELCHR);
C_DIGIPEAT: SETBOOL (ACX.RPTOK);
C_DISCONNE:
IF LS = LS1 THEN
BEGIN
WRITE20(ROEXTVAR.MSG.CANTDISC,18);
DISPLAY(C_CONNECT);
OK := FALSE;
END
ELSE
BEGIN
PTOKEN(POINT);
IF TYPTOKEN = NOTOKEN THEN
CMPRS := F_DISC
ELSE
BEGIN
OK := FALSE;
EH := TRUE;
END;
END; { DISCONNECT }
C_DISPLAY: DO_DISPLAY;
C_DWAIT: SETINT (ACX.DWAIT,0,15);
C_ECHO: SETBOOL (ACX.ECHO);
C_ESCAPE: SETBOOL (ACX.ESCAPE);
C_FLOW: SETBOOL (ACX.FLOW);
C_FRACK: SETINT (ACX.IFTIME,0,15);
C_FULLDUP: SETBOOL (ACX.FULLDUP);
C_HBAUD: SETBAUD (ACX.HBAUD, ROEXTVAR.HBAUD);
C_ID: CWID; { send cw ID }
C_IDTEXT: GETTXT(ACY.IDTXT,ACX.IDLEN);
C_LCOK: SETBOOL (ACX.LCOK);
C_LFADD: SETBOOL (ACX.LFADD);
C_MAXFRAME: SETINT (ACX.KMAX,1,7);
C_MONITOR: SETBOOL (ACX.MONON);
C_MONALL: SETBOOL(ACX.MONALL);
C_MONCON: SETBOOL (ACX.MONCON);
C_MONTO:
BEGIN
PCLIST(MON.TOLIST);
IF OK THEN
ACX.MONTO := MON.TOLIST.ALL
ELSE
EH := TRUE;
END;
C_MONFROM:
BEGIN
PCLIST(MON.FRLIST);
IF OK THEN
ACX.MONFROM := MON.FRLIST.ALL
ELSE
EH := TRUE;
END;
C_MYCALL:
BEGIN
PTOKEN(POINT);
DOCALL(ACX.MYCALL);
IF FALSE = OK THEN
EH := TRUE;
END;
C_MYVADR: SETCHR (ACX.VANID,0,31);
C_NULLS: SETINT (ACX.NULLS,0,31);
C_NUCR: SETBOOL (ACX.NUCR);
C_NULF: SETBOOL (ACX.NULF);
C_PACLEN: SETINT (ACX.PLEN,1,256);
C_PACTIME:
BEGIN
EVRYAFTR(ACX.PCEVY,ACX.PCTIME,15);
IF FALSE = OK THEN
EH := TRUE;
END;
C_PARITY: SETINT (ACX.PARITY,0,4);
C_PASS: SETCHR (ACX.PASCHR,0,127);
C_PERM: PUTNVB; { write NOVRAM and burn }
C_PROGRAM: PROGRM;
C_REDISP: SETCHR (ACX.RDSCHR,0,127);
C_RESET: RESET1;
C_RETRY: SETINT (ACX.RETRY,0,15);
C_SCREENL: SETINT (ACX.SCWID,0,255);
C_SENDPAC: SETCHR (ACX.SPCHR,0,127);
C_START: SETCHR (ACX.STRCHR,0,127);
C_STOP: SETCHR(ACX.STPCHR,0,127);
C_TRACE: SETHEX (TRACEDATA.NUMBR,-32767,32767);
C_TRANS:
BEGIN
ACX.MODEF2 := FALSE;
ACX.MODEF1 := FALSE;
SETMOD; { tell LLR - mode change }
END;
C_TXDELAY: SETINT (ACX.TXDLY,1,16);
C_TXFLOW: SETBOOL (ACX.TXF);
C_UNPROTO:
BEGIN { UNPROTO }
PTOKEN(POINT);
IF TYPTOKEN <> ALFTOKEN THEN
BEGIN
OK := FALSE;
EH := TRUE;
END
ELSE
BEGIN { alpha }
PLIT;
IF LTYPE = L_NONE THEN
BEGIN
ACX.UCONCNT := 0;
FOR II := 1 TO 6 DO
UCONLST.CALLS[FRCALLX].CALL[II] := ' ';
UCONLST.CALLS[FRCALLX].SSID := CHR(0);
END
ELSE
BEGIN { parse to call }
DOCALL(KLUDGE);
IF OK THEN
BEGIN
UCONLST.CALLS[FRCALLX] := KLUDGE;
ACX.UCONCNT := 1;
END
ELSE
EH := TRUE;
END; { parse to call }
PTOKEN(POINT);
IF TYPTOKEN <> NOTOKEN THEN
BEGIN { parse digipeaters }
PLIT;
IF TYPTOKEN <> ALFTOKEN THEN
OK := FALSE
ELSE
IF LTYPE <> L_VIA THEN
OK := FALSE;
IF OK THEN
DOCLIST(UCONLST,RPCALLX,I);
IF OK THEN
ACX.UCONCNT := I + 1
ELSE
EH := TRUE;
END; { parse digipeaters }
END; { alpha }
END; { UNPROTO }
C_VRPT: SETBOOL (ACX.VRPT);
C_VDIGIPEA: SETBOOL (ACX.VANCDP);
C_XFLOW: SETBOOL (ACX.XFLOW);
C_XMITOK: SETBOOL (ACX.XMITOK);
C_XOFF: SETCHR (ACX.XFFCHR,0,127);
C_XON: SETCHR (ACX.XONCHR,0,127);
END { CASE on CTYPE };
END;
BEGIN { COMPARSE }
GETCMD(BUF,ARS); { Get command line, no CR, Dave won't call if ARS=0 }
CMPRS := F_NULL;
OK := TRUE;
EH := FALSE;
PTOKEN(1);
IF (TYPTOKEN <> ALFTOKEN) AND (TYPTOKEN <> NOTOKEN) THEN
BEGIN
OK := FALSE;
WRITEEH(PPOINT);
END;
IF TYPTOKEN = ALFTOKEN THEN
BEGIN { find command }
PCOM;
IF CTYPE = C_LNULL THEN
BEGIN
OK := FALSE;
EH := TRUE;
END
ELSE
IF NOT ACTIONCOM(CTYPE) AND NOT SP_SKIP(POINT) THEN
DISPLAY(CTYPE)
ELSE
DOIT;
IF FALSE = OK THEN
BEGIN
IF EH THEN
WRITEEH(PPOINT);
END
ELSE
BEGIN
PTOKEN(POINT);
IF TYPTOKEN <> NOTOKEN THEN
BEGIN
WRITEDOL(PPOINT);
WRITE15(ROEXTVAR.MSG.IGNORED,13);
WRITELAST;
END;
PUTNV; { tell Margaret to repack NOVRAM }
END;
END; { find command }
IF ACX.MODEF1 THEN
WRITE5(ROEXTVAR.MSG.PROMPT,4);
COMPARSE := CMPRS;
END { COMPARSE };
PROCEDURE REALAX25;
BEGIN { REALAX25 }
ACX.UCONCNT := 1;
UCONLST.CALLS[FRCALLX].CALL := ROEXTVAR.CQ;
UCONLST.CALLS[FRCALLX].SSID := CHR(0);
LS := LS1;
TRACEDATA.BITS := [DUMPFRMR]; { dump FRMRs in hex }
MON.TOLIST.ALL := ACX.MONTO; { init from NOVRAM }
MON.FRLIST.ALL := ACX.MONFROM; { ditto }
{ Parse command input. Return with the appropriate FTYPE }
{ kludge, but it works }
IF ACX.RETRY>0 THEN
XRETRY := ACX.RETRY
ELSE
XRETRY := -1;
RETRYCNT := XRETRY;
REPEAT { forever }
LAPBPROC(F_NULL);
IF ACX.CBPRES THEN
BEGIN { process command }
PARSERES := COMPARSE;
{ kludge, but it works }
IF ACX.RETRY>0 THEN
XRETRY := ACX.RETRY
ELSE
XRETRY := -1;
LAPBPROC(PARSERES);
END { stuff to parse };
UNTIL FALSE;
END { REALAX25 };
BEGIN { AX25MAIN }
END { AX25MAIN }.